# Lista de pacotes necessários
packages <- c(
"dplyr", "ggplot2", "corrplot", "car", "lubridate",
"tidyr", "stringr", "stringi", "rstatix", "sf",
"purrr", "GGally", "FactoMineR", "factoextra",
"patchwork", "mice", "janitor", "scales", "trend"
)
# Instalar apenas os que não estão instalados
installed <- packages %in% rownames(installed.packages())
if (any(!installed)) {
install.packages(packages[!installed])
}
library(dplyr)
library(ggplot2)
library(corrplot)
library(car)
library(lubridate)
library(tidyr)
library(stringr)
library(stringi)
library(rstatix)
library(sf)
library(purrr)
library(GGally)
library(FactoMineR)
library(factoextra)
library(patchwork)
library(mice)
library(janitor)
library(scales)
library(trend)
#ler data
hypertension <- read.csv2("https://transparencia.sns.gov.pt/api/explore/v2.1/catalog/datasets/hipertensao/exports/csv?lang=pt&timezone=Europe%2FLisbon")
avc <- read.csv2("https://transparencia.sns.gov.pt/api/explore/v2.1/catalog/datasets/evolucao-situacoes-doentes-sinais-sintomas-de-avc/exports/csv?lang=pt&timezone=Europe%2FLondon&use_labels=true&delimiter=%3B")
## Vamos primeiro analisar o dataset hypertension:
#Ver missing values
out <- sapply(hypertension, function(x) sum(is.na(x) | x == ""))
#no dataframe de hipertensão existem 24 missing values na variavel ponto_ou_localizacao_geografica.
#Retiro as observações ou faço imputação? Tenho de ver se é relevante também
#avaliar relevância da variável
#ver relevância da localização para os valores de hipertenção
# Modelo completo - regressão de poisson (variável é uma contagem)
modelo_completo <- glm(contagem_de_utentes_inscritos_com_hipertensao_arterial_com_pressao_arterial_inferior_a_150_90_mmhg_n ~
ponto_ou_localizacao_geografica + regiao + tempo, data = hypertension)
# Modelo sem ponto_ou_localizacao_geografica
modelo_reduzido <- glm(contagem_de_utentes_inscritos_com_hipertensao_arterial_com_pressao_arterial_inferior_a_150_90_mmhg_n ~
regiao + tempo, data = hypertension)
# Teste de razão de verossimilhança
anova(modelo_reduzido, modelo_completo, test = "Chisq")
Analysis of Deviance Table
Model 1: contagem_de_utentes_inscritos_com_hipertensao_arterial_com_pressao_arterial_inferior_a_150_90_mmhg_n ~
regiao + tempo
Model 2: contagem_de_utentes_inscritos_com_hipertensao_arterial_com_pressao_arterial_inferior_a_150_90_mmhg_n ~
ponto_ou_localizacao_geografica + regiao + tempo
Resid. Df Resid. Dev Df Deviance Pr(>Chi)
1 6432 4.4253e+10
2 6317 1.0484e+10 115 3.3769e+10 < 2.2e-16 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
#variável relevante
total_data <- length(hypertension$ponto_ou_localizacao_geografica)
percentage_null <- 100*as.numeric(out["ponto_ou_localizacao_geografica"])/total_data
#percentagem de missing values é 0.3659 - muito pequena logo em princÃpio pode ser aceitável remove-las
#ver distribuição temporal dos valores sem localização correspondente e respetiva percentagem
where_na <- hypertension %>%
filter(ponto_ou_localizacao_geografica == "" | is.na (ponto_ou_localizacao_geografica)) %>%
count(tempo, name = "ausentes")
total_period <- hypertension %>%
count(tempo, name = "total")
percentages <- left_join(where_na, total_period, by = "tempo") %>%
mutate(percentagem = round((ausentes / total) * 100, 2))
#a percentagem sobe 5.13% , criando duvidas sobre a remoção
#comportamento dos valores sem localização correspondente
# Adiciona uma flag para missing ou não
hypertension$localizacao <- ifelse(hypertension$ponto_ou_localizacao_geografica == "" | is.na(hypertension$ponto_ou_localizacao_geografica), FALSE, TRUE)
# Compara as médias e medianas
# total de dados
metrica_total <- hypertension %>%
summarise(across(where(is.numeric), list(media = mean, mediana = median, variancia = var), na.rm = TRUE))
# dados com localização
metrica_com_local <- hypertension %>%
filter(localizacao != FALSE) %>%
summarise(across(where(is.numeric), list(media = mean, mediana = median, variancia = var), na.rm = TRUE))
#os valores das métricas comparadas não são muito discrepantes logo concluimos que a melhor abordagem é a imputação porque os dados sem localização representam a amostra, a que é confirmado pelo Welch Two Sample t-test
amostra1 <- hypertension$contagem_de_utentes_inscritos_com_hipertensao_arterial_com_pressao_arterial_inferior_a_150_90_mmhg_n
amostra2 <- hypertension %>%
filter(localizacao != FALSE) %>%
pull(contagem_de_utentes_inscritos_com_hipertensao_arterial_com_pressao_arterial_inferior_a_150_90_mmhg_n)
t.test(amostra1, amostra2, var.equal = FALSE)
Welch Two Sample t-test
data: amostra1 and amostra2
t = 0.45892, df = 13093, p-value = 0.6463
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
-96.10491 154.86345
sample estimates:
mean of x mean of y
4945.170 4915.791
# p-value= 0.6463 > 0.05 , não rejeitamos a hipotese nula. ConcluÃmos que não há diferença significativa entre as médias.
# tornar index da localização mais acessivel para que a imputação possa fazer mais sentido
# Renomear a coluna de coordenadas
hypertension <- hypertension %>%
rename(coords = ponto_ou_localizacao_geografica)
# Separar coordenadas em lat/lon
# Separar a coluna de coordenadas em latitude e longitude
hyp_coords <- hypertension %>%
separate(coords, into = c("lat", "lon"), sep = ",", convert = TRUE) %>%
mutate(
lat = as.numeric(str_replace(lat, ",", ".")),
lon = as.numeric(str_replace(lon, ",", ".")),
proporcao_hipertensos_65_a_com_pa_150_90 = as.numeric(proporcao_hipertensos_65_a_com_pa_150_90)
)
Warning: Expected 2 pieces. Missing pieces filled with `NA` in 24 rows [1244, 1248, 1253, 1286, 1322,
2503, 2521, 2529, 2537, 2545, 2572, 3880, 3909, 3914, 5207, 5225, 5250, 5262, 5277, 5286, ...].
# Garantir que a proporção esteja em formato numérico
hyp_coords <- hyp_coords %>%
mutate(proporcao_hipertensos_65_a_com_pa_150_90 = as.numeric(proporcao_hipertensos_65_a_com_pa_150_90))
# Converter para sf
hyp_sf <- hyp_coords %>%
mutate(geometry = pmap(list(lon, lat), function(x, y) {
if (is.na(x) || is.na(y)) {
st_geometrycollection()
} else {
st_point(c(x, y))
}
})) %>%
st_as_sf(crs = 4326)
# ----------------------------------
# 4. Carregar shapefiles (nÃveis 2)
# ----------------------------------
# MunicÃpios (NÃvel 2)
municipios <- st_read("gadm41_PRT_2.shp") %>% st_transform(4326)
Reading layer `gadm41_PRT_2' from data source
`/Users/marianahenriques/Documents/ProjetoBioEst/gadm41_PRT_shp/gadm41_PRT_2.shp'
using driver `ESRI Shapefile'
Simple feature collection with 308 features and 13 fields
Geometry type: MULTIPOLYGON
Dimension: XY
Bounding box: xmin: -31.26819 ymin: 30.03018 xmax: -6.189142 ymax: 42.15432
Geodetic CRS: WGS 84
municipios <- municipios %>%
rename(distritos = NAME_1,
municipio = NAME_2)
# ----------------------------------
# 5. Join espacial: Hipertensão → MunicÃpio
# ----------------------------------
hyper_joined <- st_join(hyp_sf, municipios, join = st_within)
#imputacao com base na semelhança de valores
# Calcular a média por grupo municipio
mean_per_group <- hyper_joined %>%
filter(!is.na(municipio)) %>%
group_by(municipio) %>%
summarise(mean_contagem = mean(contagem_de_utentes_inscritos_com_hipertensao_arterial_com_pressao_arterial_inferior_a_150_90_mmhg_n, na.rm = TRUE)) %>%
st_set_geometry(NULL)
desvio <- hyper_joined %>%
filter(!is.na(municipio)) %>%
group_by(municipio) %>%
summarise(desvio_contagem = sd(contagem_de_utentes_inscritos_com_hipertensao_arterial_com_pressao_arterial_inferior_a_150_90_mmhg_n, na.rm = FALSE)) %>%
st_set_geometry(NULL)
intervalo <- mean_per_group %>%
left_join(desvio, by = "municipio") %>%
mutate(
limite_inferior = mean_contagem - desvio_contagem,
limite_superior = mean_contagem + desvio_contagem
)
# Imputar municipio com base na média mais próxima da contagem
hyp_final <- hyper_joined %>%
rowwise() %>%
mutate(municipio = if_else(
is.na(municipio),
{
cont_val <- contagem_de_utentes_inscritos_com_hipertensao_arterial_com_pressao_arterial_inferior_a_150_90_mmhg_n
# Verifica quais municÃpios têm o valor dentro do intervalo
dentro_intervalo <- intervalo %>%
filter(cont_val >= limite_inferior & cont_val <= limite_superior)
if (nrow(dentro_intervalo) > 0) {
# Entre os válidos, pega o de média mais próxima
diffs <- abs(dentro_intervalo$mean_contagem - cont_val)
dentro_intervalo$municipio[which.min(diffs)]
} else {
NA_character_
}
},
municipio
)) %>%
ungroup()%>%
filter(!is.na(municipio))
tabela_correspondencia <- municipios %>%
st_drop_geometry() %>%
select(distritos, municipio) %>%
distinct()
hyp_final <- hyp_final %>%
mutate(municipio_clean = stri_trans_general(tolower(trimws(municipio)), "Latin-ASCII"))
tabela_correspondencia <- tabela_correspondencia %>%
mutate(municipio_clean = stri_trans_general(tolower(trimws(municipio)), "Latin-ASCII"))
# 2. Faz o join com base na versão limpa
hyp_final <- hyp_final %>%
left_join(tabela_correspondencia %>% select(municipio_clean, distritos), by = "municipio_clean")
# --- Efeito da imputação na média ---
# 1. Média original por grupo
mean_attr <- hyper_joined %>%
filter(!is.na(municipio)) %>%
group_by(municipio) %>%
summarise(mean_original = mean(contagem_de_utentes_inscritos_com_hipertensao_arterial_com_pressao_arterial_inferior_a_150_90_mmhg_n, na.rm = TRUE)) %>%
st_set_geometry(NULL)
# 2. Média após imputação (em hyp_final)
mean_per_group_com_imp <- hyp_final %>%
group_by(municipio) %>%
summarise(mean_imputada = mean(contagem_de_utentes_inscritos_com_hipertensao_arterial_com_pressao_arterial_inferior_a_150_90_mmhg_n, na.rm = TRUE)) %>%
st_set_geometry(NULL)
# 3. Juntar médias original e imputada
means <- left_join(mean_attr, mean_per_group_com_imp, by = "municipio")
# 4. Gráfico das médias
means_long <- means %>%
pivot_longer(cols = c(mean_original, mean_imputada),
names_to = "tipo_media",
values_to = "media")
grafico <- ggplot(means_long, aes(x = municipio, y = media, fill = tipo_media)) +
geom_col(position = "dodge") +
labs(title = "Comparação das médias por municipio",
x = "Municipio", y = "Média da contagem",
fill = "Tipo de Média") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1))
ggsave(filename = "grafico_medias_por_grupo.png", plot = grafico, width = 10, height = 6, dpi = 300)
# 5. Distância entre valor imputado e média original do grupo
distance <- hyp_final %>%
filter(localizacao == FALSE) %>%
st_set_geometry(NULL) %>%
left_join(mean_attr, by = "municipio") %>%
mutate(dist = mean_original - contagem_de_utentes_inscritos_com_hipertensao_arterial_com_pressao_arterial_inferior_a_150_90_mmhg_n)
# 6. Gráfico de linhas para analisar 5.
# Criar limites para a região sombreada (banda de confiança)
distance <- distance %>%
mutate(
ymin = mean_original - abs(dist),
ymax = mean_original + abs(dist)
)
grafico_2 <- ggplot(distance, aes(x = reorder(municipio, mean_original), y = mean_original, group = 1)) +
geom_ribbon(aes(ymin = ymin, ymax = ymax), fill = "lightblue", alpha = 0.4) + # região sombreada
geom_line(color = "blue", size = 1) + # linha da média
geom_point(aes(y = contagem_de_utentes_inscritos_com_hipertensao_arterial_com_pressao_arterial_inferior_a_150_90_mmhg_n),
color = "red", size = 2) + # pontos do valor imputado
labs(
x = "MunicÃpios com valores imputados",
y = "Valor",
title = "Média original vs distância do valor imputado",
subtitle = "Linha azul: média original; Região azul clara: distância; Pontos vermelhos: valores imputados"
) +
theme_minimal() +
theme(
axis.text.x = element_text(angle = 45, hjust = 1)
)
ggsave(filename = "grafico_distancias_por_grupo.png", plot = grafico_2, width = 10, height = 6, dpi = 300)
# --- Comparação da distribuição regional: imputados vs reais ---
tabela_comparativa <- hyp_final %>%
mutate(tipo = ifelse(localizacao, "Real", "Imputado")) %>%
group_by(municipio, tipo) %>%
summarise(total = n(), .groups = "drop") %>%
group_by(tipo) %>%
mutate(prop = total / sum(total))
p <- ggplot(tabela_comparativa, aes(x = prop, y = municipio, fill = tipo)) +
geom_col(position = "dodge") +
theme_minimal() +
labs(title = "Distribuição de MunicÃpios: Real vs Imputado",
y = "MunicÃpio", x = "Proporção") +
theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1))
ggsave("grafico_distribuicao.png", plot = p, width = 10, height = 8, dpi = 300)
# --- Correlação ---
cor_before <- cor(
hyper_joined$contagem_de_utentes_inscritos_com_hipertensao_arterial_com_pressao_arterial_inferior_a_150_90_mmhg_n,
hyper_joined$proporcao_hipertensos_65_a_com_pa_150_90,
use = "complete.obs"
)
cor_after <- cor(
hyp_final$contagem_de_utentes_inscritos_com_hipertensao_arterial_com_pressao_arterial_inferior_a_150_90_mmhg_n,
hyp_final$proporcao_hipertensos_65_a_com_pa_150_90
)
cat("Correlação antes da imputação:", cor_before, "\n")
Correlação antes da imputação: 0.7432419
cat("Correlação depois da imputação:", cor_after, "\n")
Correlação depois da imputação: 0.7427319
#summary
summary(hyper_joined %>% select(contagem_de_utentes_inscritos_com_hipertensao_arterial_com_pressao_arterial_inferior_a_150_90_mmhg_n, proporcao_hipertensos_65_a_com_pa_150_90))
contagem_de_utentes_inscritos_com_hipertensao_arterial_com_pressao_arterial_inferior_a_150_90_mmhg_n
Min. : 129
1st Qu.: 2273
Median : 4117
Mean : 4945
3rd Qu.: 6630
Max. :43441
proporcao_hipertensos_65_a_com_pa_150_90 geometry
Min. : 1.32 GEOMETRYCOLLECTION: 24
1st Qu.:18.07 POINT :6536
Median :29.83 epsg:4326 : 0
Mean :31.99 +proj=long... : 0
3rd Qu.:43.24
Max. :81.75
summary(hyp_final %>% select(contagem_de_utentes_inscritos_com_hipertensao_arterial_com_pressao_arterial_inferior_a_150_90_mmhg_n, proporcao_hipertensos_65_a_com_pa_150_90))
contagem_de_utentes_inscritos_com_hipertensao_arterial_com_pressao_arterial_inferior_a_150_90_mmhg_n
Min. : 129
1st Qu.: 2272
Median : 4115
Mean : 4935
3rd Qu.: 6627
Max. :43441
proporcao_hipertensos_65_a_com_pa_150_90 geometry
Min. : 1.32 GEOMETRYCOLLECTION: 20
1st Qu.:18.07 POINT :6536
Median :29.82 epsg:4326 : 0
Mean :31.97 +proj=long... : 0
3rd Qu.:43.18
Max. :81.75
# --- Dispersão das variáveis principais ---
ggplot(hyp_final, aes(x = contagem_de_utentes_inscritos_com_hipertensao_arterial_com_pressao_arterial_inferior_a_150_90_mmhg_n,
y = proporcao_hipertensos_65_a_com_pa_150_90,
color = localizacao)) +
geom_point() +
labs(title = "Correlação: Reais vs Imputados", color = "Dados reais?")

# --- PCA para visualização multivariada ---
dados_pca <- st_drop_geometry(hyp_final[, c("contagem_de_utentes_inscritos_com_hipertensao_arterial_com_pressao_arterial_inferior_a_150_90_mmhg_n","proporcao_hipertensos_65_a_com_pa_150_90")])
res.pca <- PCA(dados_pca, graph = FALSE)
fviz_pca_ind(res.pca,
habillage = as.factor(hyp_final$localizacao),
title = "PCA: Imputed vs Real Data",
palette = c("red", "blue")) # Vermelho = imputado, Azul = real

ggplot(hyper_joined, aes(x = contagem_de_utentes_inscritos_com_hipertensao_arterial_com_pressao_arterial_inferior_a_150_90_mmhg_n)) +
geom_histogram(bins = 30, fill = "blue", alpha = 0.5) + ggtitle("Contagem Antes da Imputação")

ggplot(hyp_final, aes(x = contagem_de_utentes_inscritos_com_hipertensao_arterial_com_pressao_arterial_inferior_a_150_90_mmhg_n)) +
geom_histogram(bins = 30, fill = "green", alpha = 0.5) + ggtitle("Contagem Depois da Imputação")

ggplot(hyper_joined, aes(x = proporcao_hipertensos_65_a_com_pa_150_90)) +
geom_histogram(bins = 30, fill = "blue", alpha = 0.5) + ggtitle("Proporção Antes da Imputação")

ggplot(hyp_final, aes(x = proporcao_hipertensos_65_a_com_pa_150_90)) +
geom_histogram(bins = 30, fill = "green", alpha = 0.5) + ggtitle("Proporção Depois da Imputação")

#imputação com sucesso
#Analise temporal do dataframe da hipertensao com imputacao
# Calcular proporção total
hyp_final <- hyp_final %>%
mutate(total = 100 * contagem_de_utentes_inscritos_com_hipertensao_arterial_com_pressao_arterial_inferior_a_150_90_mmhg_n / proporcao_hipertensos_65_a_com_pa_150_90)
# Total por ano (todos os utentes)
hipertensao_ano <- hyp_final %>%
mutate(Ano = year(ym(tempo))) %>%
group_by(Ano) %>%
summarise(total = sum(as.numeric(total), na.rm = TRUE), .groups = "drop") %>%
st_set_geometry(NULL)
ggplot(hipertensao_ano, aes(x = factor(Ano), y = total)) +
geom_col(fill = "steelblue") +
geom_text(aes(label = round(total)), vjust = -0.25, size = 3) +
labs(title = "Total de Utentes com Hipertensão por Ano",
x = "Ano",
y = "Total de Utentes") +
theme_minimal()

# Total por ano para pessoas com menos de 65 anos
hipertensao_ano_menos_65 <- hyp_final %>%
mutate(Ano = year(ym(tempo))) %>%
group_by(Ano) %>%
summarise(hip_menos_65 = sum(as.numeric(contagem_de_utentes_inscritos_com_hipertensao_arterial_com_pressao_arterial_inferior_a_150_90_mmhg_n), na.rm = TRUE), .groups = "drop") %>%
st_set_geometry(NULL)
ggplot(hipertensao_ano_menos_65, aes(x = factor(Ano), y = hip_menos_65)) +
geom_col(fill = "steelblue") +
geom_text(aes(label = round(hip_menos_65)), vjust = -0.25, size = 3) +
labs(title = "Total de Utentes com menos de 65 anos com Hipertensão por Ano",
x = "Ano",
y = "Total de Utentes") +
theme_minimal()

# Comparação entre menos de 65 e 65 ou mais
hipertensao_comp_ano <- hipertensao_ano %>%
left_join(hipertensao_ano_menos_65, by = "Ano") %>%
mutate(
hip_menos_65 = ifelse(is.na(hip_menos_65), 0, hip_menos_65),
hip_mais_65 = total - hip_menos_65
) %>%
select(Ano, hip_menos_65, hip_mais_65) %>%
pivot_longer(
cols = c(hip_menos_65, hip_mais_65),
names_to = "Group",
values_to = "total"
) %>%
mutate(
Group = dplyr::recode(Group,
"hip_menos_65" = "Under 65 years old",
"hip_mais_65" = "65 years or older")
)
# Gráfico empilhado
ggplot(hipertensao_comp_ano, aes(x = factor(Ano), y = total, fill = Group)) +
geom_col() +
labs(
title = " Controlled Hypertension by Age and Year",
x = "Year",
y = "Number of Patients"
) +
theme_minimal()

# Hipertensão por mês - Total
hipertensao_mes <- hyp_final %>%
mutate(Data = ym(tempo),
Mes = month(Data, label = TRUE, abbr = FALSE)) %>%
group_by(Mes) %>%
summarise(total = sum(as.numeric(total), na.rm = TRUE), .groups = "drop") %>%
arrange(match(Mes, month.name)) %>%
st_set_geometry(NULL)
ggplot(hipertensao_mes, aes(x = Mes, y = total)) +
geom_col(fill = "steelblue") +
geom_text(aes(label = round(total)), vjust = -0.25, size = 3) +
labs(title = "Total de Utentes com Hipertensão por Mês",
x = "Mês",
y = "Total de Utentes") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1))

# Hipertensão por mês - Menos de 65
hipertensao_mes_65 <- hyp_final %>%
mutate(Data_65 = ym(tempo),
Mes_65 = month(Data_65, label = TRUE, abbr = FALSE)) %>%
group_by(Mes_65) %>%
summarise(hip_menos_65 = sum(as.numeric(contagem_de_utentes_inscritos_com_hipertensao_arterial_com_pressao_arterial_inferior_a_150_90_mmhg_n), na.rm = TRUE), .groups = "drop") %>%
arrange(match(Mes_65, month.name)) %>%
st_set_geometry(NULL)
ggplot(hipertensao_mes_65, aes(x = Mes_65, y = hip_menos_65)) +
geom_col(fill = "steelblue") +
geom_text(aes(label = round(hip_menos_65)), vjust = -0.25, size = 3) +
labs(title = "Utentes <65 anos com Hipertensão por Mês",
x = "Mês",
y = "Total de Utentes") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1))

# Tabela de meses em português
meses_pt <- c("janeiro", "fevereiro", "março", "abril", "maio", "junho",
"julho", "agosto", "setembro", "outubro", "novembro", "dezembro")
mes_lookup <- c(
"january" = "janeiro", "february" = "fevereiro", "march" = "março",
"april" = "abril", "may" = "maio", "june" = "junho",
"july" = "julho", "august" = "agosto", "september" = "setembro",
"october" = "outubro", "november" = "novembro", "december" = "dezembro"
)
# Juntar total e <65, calcular >=65
hipertensao_comp_mes <- hipertensao_mes %>%
left_join(hipertensao_mes_65, by = c("Mes" = "Mes_65")) %>%
mutate(
hip_menos_65 = ifelse(is.na(hip_menos_65), 0, hip_menos_65),
hip_mais_65 = total - hip_menos_65,
Mes = dplyr::recode(tolower(as.character(Mes)), !!!mes_lookup),
Mes = factor(Mes, levels = meses_pt)
) %>%
select(Mes, hip_menos_65, hip_mais_65) %>%
pivot_longer(
cols = c(hip_menos_65, hip_mais_65),
names_to = "Group",
values_to = "Total_hip"
) %>%
mutate(
Group = dplyr::recode(Group,
"hip_menos_65" = "Under 65 years old",
"hip_mais_65" = "65 years or older")
)
# Gráfico final - barras egroup_by()# Gráfico final - barras empilhadas
ggplot(hipertensao_comp_mes, aes(x = Mes, y = Total_hip, fill = Group)) +
geom_col() +
labs(
title = " Controlled Hypertension by Age and Month",
x = "Month",
y = "Number of patients"
) +
theme_minimal() +
theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1))

## Análise do dataset avc:
#Quais os anos e meses é que estão registados no AVC
meses_por_ano_avc <- avc %>%
mutate(Ano_avc = year(ym(PerÃodo)),
Mes_avc = month(ym(PerÃodo), label = TRUE, abbr = FALSE)) %>%
distinct(Ano_avc, Mes_avc) %>%
arrange(Ano_avc, Mes_avc) %>%
group_by(Ano_avc) %>%
summarise(Meses_Disponiveis = paste(Mes_avc, collapse = ", "))
#Ver missing values
sapply(avc, function(x) sum(is.na(x) | x == ""))
N.º.Registos PerÃodo Distrito.da.Ocorrência
0 0 0
Concelho.da.Ocorrência Faixa.Etária.da.VÃtima Género.da.VÃtima
0 0 0
Hospital.de.Destino N.º.de.registos.Via.Verde.AVC
0 0
# Distribuição por Género com AVC
avc_genero <- avc %>%
group_by(Género.da.VÃtima) %>%
summarise(Total_AVC = sum(as.numeric(`N.º.de.registos.Via.Verde.AVC`), na.rm = TRUE)) %>%
arrange(desc(Total_AVC))
ggplot(avc_genero, aes(x = reorder(Género.da.VÃtima, -Total_AVC), y = Total_AVC, fill = Género.da.VÃtima)) +
geom_col() +
geom_text(aes(label = Total_AVC), vjust = -0.2, size = 2) +
labs(title = "Total de Registos de AVC por Género",
x = "Género",
y = "Total de AVC") +
theme_minimal()

# Distribuição por Género com AVC em cada ano
avc_genero_ano <- avc %>%
mutate(Ano = year(ym(PerÃodo))) %>%
group_by(Ano, Género.da.VÃtima) %>%
summarise(Total_AVC = sum(as.numeric(N.º.de.registos.Via.Verde.AVC), na.rm = TRUE), .groups = "drop")
# Traduzir valores de 'Género.da.VÃtima'
avc$Género.da.VÃtima <- ifelse(avc$Género.da.VÃtima == "Feminino", "Female",
ifelse(avc$Género.da.VÃtima == "Masculino", "Male", avc$Género.da.VÃtima))
ggplot(avc_genero_ano, aes(x = factor(Ano), y = Total_AVC, fill = Género.da.VÃtima)) +
geom_col(position = "dodge") +
geom_text(aes(label = Total_AVC), position = position_dodge(width = 0.9), vjust = -0.25, size = 3) +
labs(title = "Total Stroke Records by Year and Gender",
x = "Year",
y = "Total Stroke Records",
fill = "Gender") +
theme_minimal()

# Distribuição por Género com AVC em cada mês
avc_genero_mes <- avc %>%
mutate(Mes_Ano = format(ym(PerÃodo), "%Y-%m")) %>%
group_by(Mes_Ano, `Género.da.VÃtima`) %>%
summarise(Total_AVC = sum(as.numeric(`N.º.de.registos.Via.Verde.AVC`), na.rm = TRUE), .groups = "drop")
ggplot(avc_genero_mes, aes(x = Mes_Ano, y = Total_AVC, fill = `Género.da.VÃtima`)) +
geom_col(position = "dodge") +
labs(title = "Stroke Distribution by Month and Gender",
x = "Month", y = "Total Stroke Records", fill = "Gender") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1))

# Distribuição Faixa Etária com AVC no total dos anos
# Define the correct order of age ranges
faixa_ordem <- c("0 - 17", "18 - 29", "30 - 39", "40 - 49", "50 - 59",
"60 - 69", "70 - 79", "80 - 89", "90 - 99", ">100")
# Apply the order using factor
avc_idade <- avc %>%
group_by(`Faixa.Etária.da.VÃtima`) %>%
summarise(Total_AVC = sum(as.numeric(`N.º.de.registos.Via.Verde.AVC`), na.rm = TRUE)) %>%
mutate(`Faixa.Etária.da.VÃtima` = factor(`Faixa.Etária.da.VÃtima`, levels = faixa_ordem)) %>%
arrange(`Faixa.Etária.da.VÃtima`)
# Plot
ggplot(avc_idade, aes(x = `Faixa.Etária.da.VÃtima`, y = Total_AVC)) +
geom_col(fill = "steelblue") +
geom_text(aes(label = Total_AVC), vjust = -0.2, size = 2) +
labs(title = "Total de Registos de AVC por Faixa Etária",
x = "Faixa Etária",
y = "Total de AVC") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1))

# Distribuição Faixa Etária com AVC em cada ano
avc_faixa_ano <- avc %>%
mutate(Ano = year(ym(PerÃodo))) %>%
group_by(Ano, `Faixa.Etária.da.VÃtima`) %>%
summarise(Total_AVC = sum(as.numeric(`N.º.de.registos.Via.Verde.AVC`), na.rm = TRUE), .groups = "drop") %>% mutate(`Faixa.Etária.da.VÃtima` = factor(`Faixa.Etária.da.VÃtima`, levels = faixa_ordem)) %>%
arrange(`Faixa.Etária.da.VÃtima`)
ggplot(avc_faixa_ano, aes(x = factor(Ano), y = Total_AVC, fill = `Faixa.Etária.da.VÃtima`)) +
geom_col(position = "dodge") +
labs(title = "Total Stroke Records by Year and Age Group",
x = "Year",
y = "Total Stroke Records",
fill = "Age Group") +
theme_minimal()

# Distribuição Faixa Etária com AVC em cada mês
avc_faixa_mes <- avc %>%
mutate(Mes_Ano = format(ym(PerÃodo), "%Y-%m")) %>%
group_by(Mes_Ano, `Faixa.Etária.da.VÃtima`) %>%
summarise(Total_AVC = sum(as.numeric(`N.º.de.registos.Via.Verde.AVC`), na.rm = TRUE), .groups = "drop") %>% mutate(`Faixa.Etária.da.VÃtima` = factor(`Faixa.Etária.da.VÃtima`, levels = faixa_ordem)) %>%
arrange(`Faixa.Etária.da.VÃtima`)
ggplot(avc_faixa_mes, aes(x = Mes_Ano, y = Total_AVC, fill = `Faixa.Etária.da.VÃtima`)) +
geom_col(position = "dodge") +
labs(title = "Stroke Distribution by Month and Age Group",
x = "Month", y = "Total Stroke Records", fill = "Age Groupe") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1))

# Género × Faixa Etária ao longos do perÃodo
avc_cross <- avc %>%
group_by(`Género.da.VÃtima`, `Faixa.Etária.da.VÃtima`) %>%
summarise(Total_AVC = sum(as.numeric(`N.º.de.registos.Via.Verde.AVC`), na.rm = TRUE)) %>%
ungroup() %>% mutate(`Faixa.Etária.da.VÃtima` = factor(`Faixa.Etária.da.VÃtima`, levels = faixa_ordem)) %>%
arrange(`Faixa.Etária.da.VÃtima`)
`summarise()` has grouped output by 'Género.da.VÃtima'. You can override using the `.groups`
argument.
ggplot(avc_cross, aes(x = `Faixa.Etária.da.VÃtima`, y = Total_AVC, fill = `Género.da.VÃtima`)) +
geom_col(position = "dodge") +
labs(title = "Distribuição de AVC por Género e Faixa Etária", x = "Faixa Etária", y = "Total de AVC", fill = "Género") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1))

# Correlação entre Hipertensos e AVC por grupo etário (maiores de 65 anos e menores de 65 anos)
# Clean names
avc <- avc %>% janitor::clean_names()
# Fix column name
names(avc)[names(avc) == "n_o_de_registos_via_verde_avc"] <- "n_de_registos_via_verde_avc"
# Dividimos o AVC em maiores de 65 anos e menores de 65 anos
avc_clean <- avc %>%
mutate(
faixa_inicio = as.numeric(str_extract(faixa_etaria_da_vitima, "^\\d+")),
faixa_fim = as.numeric(str_extract(faixa_etaria_da_vitima, "\\d+$")),
Group = case_when(
faixa_inicio < 69 ~ "Under 65 years old",
TRUE ~ "65 years or older"
),
mes_num = as.integer(str_sub(periodo, 6, 7)),
mes = factor(meses_pt[mes_num], levels = meses_pt),
n_de_registos_via_verde_avc = as.numeric(n_de_registos_via_verde_avc)
) %>%
group_by(mes, Group) %>%
summarise(total_avc = sum(n_de_registos_via_verde_avc, na.rm = TRUE), .groups = "drop")
# Filtrar dados de hipertensão de 2022-01 a 2024-02
hyp_filtrado <- hyp_final %>%
st_set_geometry(NULL) %>%
mutate(Data = ym(tempo)) %>%
filter(Data >= ym("2022-01") & Data <= ym("2024-02"))
# Hipertensão total por mês
hipertensao_mes_filtrado <- hyp_filtrado %>%
mutate(Mes = month(Data, label = TRUE, abbr = FALSE)) %>%
group_by(Mes) %>%
summarise(total = sum(as.numeric(total), na.rm = TRUE), .groups = "drop") %>%
arrange(match(Mes, month.name))
# Hipertensão em menores de 65 anos
hipertensao_mes_65_filtrado <- hyp_filtrado %>%
mutate(Mes = month(Data, label = TRUE, abbr = FALSE)) %>%
group_by(Mes) %>%
summarise(hip_65 = sum(as.numeric(contagem_de_utentes_inscritos_com_hipertensao_arterial_com_pressao_arterial_inferior_a_150_90_mmhg_n), na.rm = TRUE), .groups = "drop") %>%
arrange(match(Mes, month.name))
# Combinar dados de hipertensão e preparar formato longo
hipertensao_comp_mes_filtrado <- hipertensao_mes_filtrado %>%
left_join(hipertensao_mes_65_filtrado, by = "Mes") %>%
mutate(
hip_65 = ifelse(is.na(hip_65), 0, hip_65),
hip_mais_65 = total - hip_65,
Mes = mes_lookup[Mes],
Mes = factor(Mes, levels = meses_pt)
) %>%
select(Mes, hip_65, hip_mais_65) %>%
pivot_longer(
cols = c("hip_65", "hip_mais_65"),
names_to = "Group",
values_to = "Total_hip"
) %>%
mutate(
Group = dplyr::recode(Group,
"hip_65" = "Under 65 years old",
"hip_mais_65" = "65 years or older")
)
# Gráfico empilhado de hipertensão
ggplot(hipertensao_comp_mes_filtrado, aes(x = Mes, y = Total_hip, fill = Group)) +
geom_col() +
labs(
title = "Hipertensão por Idade e Mês (2022-01 a 2024-02)",
x = "Mês",
y = "Número de Utentes"
) +
theme_minimal() +
theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1))

# Resumo para análise
hipertensao_summary <- hipertensao_comp_mes_filtrado %>%
group_by(Mes, Group) %>%
summarise(Total_HIP = sum(Total_hip), .groups = "drop") %>%
rename(mes = Mes)
# Merge com dados de AVC
merged <- left_join(hipertensao_summary, avc_clean, by = c("mes", "Group"))
# Boxplots para visualização de outliers
ggplot(merged, aes(x = Group, y = Total_HIP)) +
geom_boxplot() +
labs(title = "Boxplot of Controlled Hypertension by Age Group", x="Group", y="Total Hypertension Patients")

ggplot(merged, aes(x = Group, y = total_avc)) +
geom_boxplot() +
labs(title = "Boxplot of Stroke Cases by Age Group", x="Group", y="Total Stroke Cases")

#como há outliers, fazemos com o spearman
# Correlação de Spearman
cor_results_spearman <- merged %>%
group_by(Group) %>%
summarise(correl = cor(Total_HIP, total_avc, method = "spearman"))
print(cor_results_spearman)
# Scatterplot com regressão para visualização
ggplot(merged, aes(x = Total_HIP, y = total_avc, color = Group)) +
geom_point(size = 3) +
geom_smooth(method = "lm", se = FALSE) +
facet_wrap(~ Group) +
labs(
title = "Correlation between Controlled Hypertension and Stroke by Age Group",
x = "Total Hypertension Patients",
y = "Total Stroke Cases"
) +
theme_minimal()
`geom_smooth()` using formula = 'y ~ x'

# Regressões lineares por grupo
models <- merged %>%
group_by(Group) %>%
group_map(~ lm(total_avc ~ Total_HIP, data = .x), .keep = TRUE)
# Resumo das regressões
summary(models[[1]]) # Under 65 years old
Call:
lm(formula = total_avc ~ Total_HIP, data = .x)
Residuals:
Min 1Q Median 3Q Max
-152.51 -36.62 16.85 56.54 106.31
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 4.703e+02 7.398e+01 6.357 8.28e-05 ***
Total_HIP 3.116e-04 5.918e-05 5.266 0.000365 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 82.79 on 10 degrees of freedom
Multiple R-squared: 0.735, Adjusted R-squared: 0.7085
F-statistic: 27.73 on 1 and 10 DF, p-value: 0.0003649
summary(models[[2]]) # 65 years or older
Call:
lm(formula = total_avc ~ Total_HIP, data = .x)
Residuals:
Min 1Q Median 3Q Max
-83.16 -29.66 -13.39 10.95 148.96
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 4.935e+02 5.092e+01 9.691 2.12e-06 ***
Total_HIP -1.397e-04 8.325e-05 -1.679 0.124
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 64.71 on 10 degrees of freedom
Multiple R-squared: 0.2198, Adjusted R-squared: 0.1418
F-statistic: 2.817 on 1 and 10 DF, p-value: 0.1242
# Total de Registos de AVC por Distrito
avc_regiao <- avc %>%
group_by(`distrito_da_ocorrencia`) %>%
summarise(Total_AVC = sum(as.numeric(`n_de_registos_via_verde_avc`), na.rm = TRUE)) %>%
arrange(desc(Total_AVC))
ggplot(avc_regiao, aes(x = reorder(`distrito_da_ocorrencia`, -Total_AVC), y = Total_AVC)) +
geom_col(fill = "steelblue") +
geom_text(aes(label = Total_AVC), vjust = -0.2, size = 2) +
labs(title = "Total Stroke Records by District",
x = "District", y = "Patients") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1))

# Distribuição ao longo do tempo por distrito
avc_regiao_tempo <- avc %>%
mutate(Mes_Ano = format(ym(periodo), "%Y-%m")) %>%
group_by(Mes_Ano, `distrito_da_ocorrencia`) %>%
summarise(Total_AVC = sum(as.numeric(`n_de_registos_via_verde_avc`), na.rm = TRUE), .groups = "drop")
ggplot(avc_regiao_tempo, aes(x = Mes_Ano, y = Total_AVC, color = `distrito_da_ocorrencia`, group = `distrito_da_ocorrencia`)) +
geom_line() +
labs(title = "Evolução Mensal de Registos de AVC por Distrito",
x = "Mês", y = "Total de AVC", color = "Distrito") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1))

## Ir buscar o número de habitantes por distrito em portugal em 2022, 2023 e 2024 e fazer média, para normalizar e poder comparar, porque obviamente que no porto e lisboa há maior numero de avc porque há mais habitantes.
# Vetor com as populações médias estimadas
populacao_distritos <- c(
"Lisboa" = 2318952,
"Porto" = 1829758,
"Setúbal" = 893464,
"Braga" = 858708,
"Aveiro" = 717998,
"Faro" = 474500,
"Leiria" = 471570,
"Santarém" = 436891,
"Coimbra" = 413225,
"Viseu" = 364020,
"Madeira" = 254630,
"Açores" = 241471,
"Viana do Castelo" = 233610,
"Vila Real" = 185263,
"Castelo Branco" = 178860,
"Évora" = 153427,
"Beja" = 147363,
"Guarda" = 142131,
"Bragança" = 123109,
"Portalegre" = 104561
)
# Adicionar população ao DataFrame
avc_regiao_tempo <- avc_regiao_tempo %>%
mutate(Populacao = populacao_distritos[`distrito_da_ocorrencia`],
Taxa_AVC = (Total_AVC / Populacao) * 100000)
# Média da taxa de AVC por distrito
ranking_distritos <- avc_regiao_tempo %>%
group_by(`distrito_da_ocorrencia`) %>%
summarise(Media_Taxa_AVC = mean(Taxa_AVC, na.rm = TRUE)) %>%
arrange(desc(Media_Taxa_AVC))
print(ranking_distritos)
ggplot(ranking_distritos, aes(x = reorder(`distrito_da_ocorrencia`, Media_Taxa_AVC), y = Media_Taxa_AVC)) +
geom_col(fill = "darkred") +
geom_text(aes(label = round(Media_Taxa_AVC, 1)), hjust = -0.1, size = 3) +
coord_flip() +
labs(title = "Stroke Rate by District",
x = "District", y = "Rate") +
theme_minimal()

# Visualizar as taxas de AVC ao longo do tempo por distrito
ggplot(avc_regiao_tempo, aes(x = Mes_Ano, y = Taxa_AVC, color = `distrito_da_ocorrencia`, group = `distrito_da_ocorrencia`)) +
geom_line() +
labs(title = "Evolução Mensal da Taxa de AVC por Distrito",
x = "Mês", y = "Taxa de AVC por 100.000 habitantes", color = "Distrito") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1))

#Como não é possivel comparar bem pelo gráfico, vamos fazer testes estatitisticos.
#vamos ver primeiro se o total_avc tem distribuição normal em todos os distritos
ggplot(avc_regiao_tempo, aes(x = Taxa_AVC)) +
geom_histogram(bins = 15, fill = "skyblue", color = "black") +
facet_wrap(~ `distrito_da_ocorrencia`, scales = "free") +
theme_minimal()

# Aplicar o teste shapiro
shapiro_results <- avc_regiao_tempo %>%
group_by(distrito_da_ocorrencia) %>%
summarise(p_value = shapiro.test(Taxa_AVC)$p.value)
# Print
print(shapiro_results)
# Homogeneidade das variâncias entre os grupos
levene_result <- leveneTest(Taxa_AVC ~ distrito_da_ocorrencia, data = avc_regiao_tempo)
Warning in leveneTest.default(y = y, group = group, ...) :
group coerced to factor.
# Printar o resultado
print(levene_result)
Levene's Test for Homogeneity of Variance (center = median)
Df F value Pr(>F)
group 17 9.8049 < 2.2e-16 ***
450
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
#conclusão: os dados são distribuidos normalmente e as variâncias são significativamente diferentes. Logo, vamos fazer o teste Welch ANOVA (oneway.test) para comparar as médias das taxas de AVC por 100.000 habitantes entre distritos, sem assumir variâncias iguais.
# Welch ANOVA
oneway.test(Taxa_AVC ~ `distrito_da_ocorrencia`, data = avc_regiao_tempo, var.equal = FALSE)
One-way analysis of means (not assuming equal variances)
data: Taxa_AVC and distrito_da_ocorrencia
F = 32.86, num df = 17.00, denom df = 167.03, p-value < 2.2e-16
#vamos ver como a taxa média de AVC evoluiu ao longo dos anos por distrito
avc_regiao_tempo <- avc_regiao_tempo %>%
mutate(Ano = substr(Mes_Ano, 1, 4)) # extrai os 4 primeiros caracteres como ano
media_anual_distrito <- avc_regiao_tempo %>%
group_by(Ano, `distrito_da_ocorrencia`) %>%
summarise(Media_Taxa_AVC = mean(Taxa_AVC, na.rm = TRUE), .groups = "drop")
ggplot(media_anual_distrito, aes(x = Ano, y = Media_Taxa_AVC, color = `distrito_da_ocorrencia`, group = `distrito_da_ocorrencia`)) +
geom_line(size = 1) +
geom_point(size = 1.5) +
labs(title = "Evolução Anual da Taxa de AVC por Distrito",
x = "Ano",
y = "Taxa média de AVC por 100.000 habitantes",
color = "Distrito") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1))

# Heatmap
ggplot(media_anual_distrito, aes(x = Ano, y = reorder(`distrito_da_ocorrencia`, -Media_Taxa_AVC))) +
geom_tile(aes(fill = Media_Taxa_AVC), color = "white") +
scale_fill_gradient(low = "white", high = "red") +
labs(title = "Heat Map: Stroke Rate by District and Year",
x = "Year",
y = "District",
fill = "Rate") +
theme_minimal()

## A mesma análise mas para hipertensos
# 1. Dados mensais filtrados (2022-01 a 2024-02)
hipertensao_tempo <- hyp_final %>%
mutate(Mes_Ano = format(ym(tempo), "%Y-%m")) %>%
filter(Mes_Ano >= "2022-01", Mes_Ano <= "2024-02") %>%
group_by(Mes_Ano, distritos.x) %>%
summarise(
Total_Hipertensao_Controlada = sum(as.numeric(total),na.rm = TRUE),
.groups = "drop") %>%
mutate( Populacao = populacao_distritos[distritos.x],
Taxa_Hipertensao_Controlada = (Total_Hipertensao_Controlada / Populacao) * 100000
)%>%
st_drop_geometry(hipertensao_tempo)%>%
rename(Distrito = distritos.x)
# 2. Total acumulado por distrito
hipertensao_total <- hipertensao_tempo %>%
group_by(Distrito) %>%
summarise(Total_Hipertensao_Controlada = sum(Total_Hipertensao_Controlada, na.rm = TRUE)) %>%
arrange(desc(Total_Hipertensao_Controlada))
# Gráfico de total acumulado
ggplot(hipertensao_total, aes(x = reorder(Distrito, -Total_Hipertensao_Controlada), y = Total_Hipertensao_Controlada)) +
geom_col(fill = "steelblue") +
geom_text(aes(label = round(Total_Hipertensao_Controlada)), vjust = -0.2, size = 2) +
labs(title = "Total Patients with Controlled Hypertension by District",
x = "District", y = "Patients") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1))

# Distribuição ao longo do tempo por distrito
ggplot(hipertensao_tempo, aes(x = Mes_Ano, y = Total_Hipertensao_Controlada, color = `Distrito`, group = `Distrito`)) +
geom_line() +
labs(title = "Evolução Mensal de Registos de hipertensao por Distrito",
x = "Mês", y = "Total de Hipertensão", color = "Distrito") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1))

# 3. Gráfico de evolução mensal das taxas
ggplot(hipertensao_tempo, aes(x = Mes_Ano, y = Taxa_Hipertensao_Controlada, color = Distrito, group = Distrito)) +
geom_line() +
labs(title = "Evolução mensal da Taxa de Hipertensão Controlada por Distrito",
x = "Mês", y = "Taxa de Hipertensão por 100.000 habitantes", color = "Distrito") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1
))

# 4. Média da taxa por distrito
ranking_distritos <- hipertensao_tempo %>%
group_by(Distrito) %>%
summarise(Media_Taxa_Hipertensao_Controlada = mean(Taxa_Hipertensao_Controlada, na.rm = TRUE)) %>%
arrange(desc(Media_Taxa_Hipertensao_Controlada))
# Gráfico de ranking das taxas médias
ggplot(ranking_distritos, aes(x = reorder(Distrito, Media_Taxa_Hipertensao_Controlada), y = Media_Taxa_Hipertensao_Controlada)) +
geom_col(fill = "darkgreen") +
geom_text(aes(label = round(Media_Taxa_Hipertensao_Controlada, 1)), hjust = -0.1, size = 2) +
coord_flip() +
labs(title = "Controlled Hypertension Rate by District",
x = "District", y = "Rate") +
theme_minimal()

# 5. Histogramas por distrito (distribuição das taxas)
ggplot(hipertensao_tempo, aes(x = Taxa_Hipertensao_Controlada)) +
geom_histogram(bins = 15, fill = "skyblue", color = "black") +
facet_wrap(~ Distrito, scales = "free") +
theme_minimal()

# 6. Teste de normalidade (Shapiro-Wilk)
shapiro_results <- hipertensao_tempo %>%
group_by(Distrito) %>%
summarise(p_value = shapiro.test(Taxa_Hipertensao_Controlada)$p.value)
print(shapiro_results)
# 7. Teste de homogeneidade das variâncias (Levene)
leveneTest(Taxa_Hipertensao_Controlada ~ Distrito, data = hipertensao_tempo)
Warning in leveneTest.default(y = y, group = group, ...) :
group coerced to factor.
Levene's Test for Homogeneity of Variance (center = median)
Df F value Pr(>F)
group 17 1.9335 0.01402 *
449
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
kruskal.test(Taxa_Hipertensao_Controlada ~ Distrito, data = hipertensao_tempo)
Kruskal-Wallis rank sum test
data: Taxa_Hipertensao_Controlada by Distrito
Kruskal-Wallis chi-squared = 406.15, df = 17, p-value < 2.2e-16
# Partindo do objeto `hipertensao_tempo` já existente e filtrado (2022-2024)
# 1. Extrair o ano
hipertensao_tempo <- hipertensao_tempo %>%
mutate(Ano = substr(Mes_Ano, 1, 4))
# 2. Calcular média anual da taxa por distrito
media_anual_distrito <- hipertensao_tempo %>%
group_by(Ano, Distrito) %>%
summarise(Media_Taxa_Hipertensao_Controlada = mean(Taxa_Hipertensao_Controlada, na.rm = TRUE), .groups = "drop")
# 3. Gráfico de linhas: Evolução anual
ggplot(media_anual_distrito, aes(x = Ano, y = Media_Taxa_Hipertensao_Controlada, color = Distrito, group = Distrito)) +
geom_line(size = 1) +
geom_point(size = 1.5) +
labs(title = "Evolução Anual da Taxa de Hipertensão Controlada por Distrito",
x = "Ano",
y = "Taxa média por 100.000 habitantes",
color = "Distrito") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1))

# 4. Heatmap: Mapa de calor por distrito e ano
ggplot(media_anual_distrito, aes(x = Ano, y = reorder(Distrito, -Media_Taxa_Hipertensao_Controlada))) +
geom_tile(aes(fill = Media_Taxa_Hipertensao_Controlada), color = "white") +
scale_fill_gradient(low = "white", high = "darkgreen") +
labs(title = "Heat Map: Controlled Hypertension Rate by District and Year",
x = "Year",
y = "District",
fill = "Rate") +
theme_minimal()

#Vamos ajustar uma regressão linear da taxa média anual vs ano para cada distrito e ver o coeficiente da inclinação:
# Converter o ano para numérico
media_anual_distrito$Ano_Num <- as.numeric(media_anual_distrito$Ano)
# Regressão linear por distrito
tendencias <- media_anual_distrito %>%
group_by(Distrito) %>%
summarise(
inclinacao = coef(lm(Media_Taxa_Hipertensao_Controlada ~ Ano_Num))[2],
p_valor = summary(lm(Media_Taxa_Hipertensao_Controlada ~ Ano_Num))$coefficients[2, 4]
) %>%
arrange(inclinacao)
print(tendencias)
# Aplica o teste de Mann-Kendall globalmente
mk.test(media_anual_distrito$Media_Taxa_Hipertensao_Controlada)
Mann-Kendall trend test
data: media_anual_distrito$Media_Taxa_Hipertensao_Controlada
z = 0.13429, n = 54, p-value = 0.8932
alternative hypothesis: true S is not equal to 0
sample estimates:
S varS tau
1.900000e+01 1.796700e+04 1.327743e-02
modelo_global <- lm(Media_Taxa_Hipertensao_Controlada ~ Ano_Num, data = media_anual_distrito)
summary(modelo_global)
Call:
lm(formula = Media_Taxa_Hipertensao_Controlada ~ Ano_Num, data = media_anual_distrito)
Residuals:
Min 1Q Median 3Q Max
-2966.1 -935.5 -27.2 1123.1 4027.1
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -27207.58 431123.04 -0.063 0.950
Ano_Num 17.59 213.11 0.083 0.935
Residual standard error: 1279 on 52 degrees of freedom
Multiple R-squared: 0.000131, Adjusted R-squared: -0.0191
F-statistic: 0.006813 on 1 and 52 DF, p-value: 0.9345
## COMPARAÇÃO COM AS TAXAS NOS ANOS COMUNS
# AVC
avc_regiao <- avc %>%
group_by(`distrito_da_ocorrencia`) %>%
summarise(Total_AVC = sum(as.numeric(`n_de_registos_via_verde_avc`), na.rm = TRUE)) %>%
rename(Distrito = `distrito_da_ocorrencia`)
# Hipertensão
hipertensao_total <- hipertensao_tempo %>%
group_by(Distrito) %>%
summarise(Total_Hipertensao_Controlada = sum(Total_Hipertensao_Controlada, na.rm = TRUE))
# Juntar
df_relacao <- full_join(avc_regiao, hipertensao_total, by = "Distrito") %>%
mutate(
Populacao = populacao_distritos[Distrito],
Taxa_AVC = (Total_AVC / Populacao) * 100000,
Taxa_Hipertensao_Controlada = (Total_Hipertensao_Controlada / Populacao) * 100000
) %>%
drop_na()
ggplot(df_relacao, aes(x = Taxa_Hipertensao_Controlada, y = Taxa_AVC)) +
geom_point(color = "darkblue", size = 3) +
geom_smooth(method = "lm", se = TRUE, color = "red") +
geom_text(aes(label = Distrito), vjust = -0.8, size = 3) +
labs(title = "Relationship between Controlled Hypertension Rate and Stroke Rate by District",
x = "Controlled Hypertension Rate per 100,000 inhabitants",
y = "Stroke Rate per 100,000 inhabitants") +
theme_minimal()
`geom_smooth()` using formula = 'y ~ x'

# ver se tenho outliers
boxplot(df_relacao$Taxa_Hipertensao_Controlada,
main = "Boxplot of Controlled Hypertension Rate by District",
ylab = "Rate")

# Boxplot for Stroke Rate
boxplot(df_relacao$Taxa_AVC,
main = "Boxplot of Stroke Rate by District",
ylab = "Rate")

# Para Taxa_Hipertensao_Controlada
x <- df_relacao$Taxa_Hipertensao_Controlada
Q1 <- quantile(x, 0.25, na.rm = TRUE)
Q3 <- quantile(x, 0.75, na.rm = TRUE)
IQR <- Q3 - Q1
# Limites inferior e superior
lim_inf <- Q1 - 1.5 * IQR
lim_sup <- Q3 + 1.5 * IQR
# Ver quais são os outliers
outliers <- x[x < lim_inf | x > lim_sup]
print(outliers)
named numeric(0)
#Não tem outliers
#
# Correlação
cor.test(df_relacao$Taxa_Hipertensao_Controlada, df_relacao$Taxa_AVC, method = "pearson")
Pearson's product-moment correlation
data: df_relacao$Taxa_Hipertensao_Controlada and df_relacao$Taxa_AVC
t = -1.4182, df = 16, p-value = 0.1753
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
-0.6929269 0.1572414
sample estimates:
cor
-0.3341598
# Regressão
summary(lm(Taxa_AVC ~ Taxa_Hipertensao_Controlada, data = df_relacao))
Call:
lm(formula = Taxa_AVC ~ Taxa_Hipertensao_Controlada, data = df_relacao)
Residuals:
Min 1Q Median 3Q Max
-68.30 -28.38 -18.96 27.39 106.73
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 3.016e+02 9.846e+01 3.063 0.00743 **
Taxa_Hipertensao_Controlada -6.371e-04 4.493e-04 -1.418 0.17533
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 49.4 on 16 degrees of freedom
Multiple R-squared: 0.1117, Adjusted R-squared: 0.05614
F-statistic: 2.011 on 1 and 16 DF, p-value: 0.1753
# Juntar por Distrito e Mês
avc_regiao_tempo <- avc_regiao_tempo %>%
rename(Distrito = distrito_da_ocorrencia)
dados_mensais_combinados <- inner_join(avc_regiao_tempo, hipertensao_tempo,
by = c("Mes_Ano", "Distrito"),
suffix = c("_AVC", "_Hipertensao")) %>%
select(Mes_Ano, Distrito, Taxa_AVC, Taxa_Hipertensao_Controlada)
# Correlação de Pearson por distrito
correlacoes_distrito <- dados_mensais_combinados %>%
group_by(Distrito) %>%
summarise(
correlacao = cor(Taxa_AVC, Taxa_Hipertensao_Controlada, use = "complete.obs", method = "pearson"),
.groups = "drop"
) %>%
arrange(correlacao)
print(correlacoes_distrito)
ggplot(correlacoes_distrito, aes(x = reorder(Distrito, correlacao), y = correlacao)) +
geom_col(fill = "purple") +
geom_text(aes(label = round(correlacao, 2)), hjust = -0.2, size = 3) +
coord_flip() +
labs(title = "Correlação entre Taxa de AVC e Hipertensão Controlada por Distrito",
x = "Distrito", y = "Correlação (r)") +
theme_minimal()

# Juntar os dados mensais
dados_mensais_combinados <- inner_join(avc_regiao_tempo, hipertensao_tempo,
by = c("Mes_Ano", "Distrito"),
suffix = c("_AVC", "_Hipertensao")) %>%
select(Mes_Ano, Distrito, Taxa_AVC, Taxa_Hipertensao_Controlada)
# Calcular correlação e p-valor por distrito
correlacoes_distrito <- dados_mensais_combinados %>%
group_by(Distrito) %>%
summarise(
r = cor(Taxa_AVC, Taxa_Hipertensao_Controlada, use = "complete.obs", method = "pearson"),
p_value = cor.test(Taxa_AVC, Taxa_Hipertensao_Controlada)$p.value,
.groups = "drop"
) %>%
arrange(r)
# Ver distritos com correlação negativa significativa
correlacoes_significativas <- correlacoes_distrito %>%
filter(r < -0.3, p_value < 0.05)
print(correlacoes_significativas)
ggplot(correlacoes_distrito, aes(x = reorder(Distrito, r), y = r, fill = p_value < 0.05 & r < -0.3)) +
geom_col() +
geom_text(aes(label = round(r, 2)), hjust = -0.2, size = 3) +
coord_flip() +
scale_fill_manual(values = c("grey70", "darkred"), labels = c("Não significativa", "Significativa"), name = "Correlação negativa significativa") +
labs(title = "Correlação entre Hipertensão Controlada e AVC por Distrito",
x = "Distrito", y = "Coeficiente de Correlação (r)") +
theme_minimal()

NA
NA
# Correlação entre hipertenção e avc com as taxas
# Considerando o maior perÃodo de tempo dado pela data
#população média pr distritos entre 2015 e 2023
populacao_media <- c(
Lisboa = 2276293,
Porto = 1795549,
Setubal = 869770,
Braga = 843697,
Aveiro = 703022,
Faro = 462522,
Leiria = 457242,
Santarem = 437520,
Coimbra = 411935,
Viseu = 362275,
Madeira = 251025,
Acores = 238127,
Viana_do_Castelo = 234672,
Vila_Real = 195422,
Castelo_Branco = 183996,
Evora = 155441,
Beja = 144772,
Guarda = 148932,
Braganca = 127356,
Portalegre = 109975
)
hipertensao_tempo_all <- hyp_final %>%
mutate(Mes_Ano = format(ym(tempo), "%Y-%m")) %>%
group_by(Mes_Ano, distritos.x) %>%
summarise(
Total_Hipertensao_Controlada = sum(as.numeric(total), na.rm = TRUE),
.groups = "drop"
) %>%
mutate(
Populacao = populacao_media[distritos.x],
Taxa_Hipertensao_Controlada = (Total_Hipertensao_Controlada / populacao_media) * 100000
)
Warning: There was 1 warning in `stopifnot()`.
ℹ In argument: `Taxa_Hipertensao_Controlada = (Total_Hipertensao_Controlada/populacao_media) *
1e+05`.
Caused by warning in `Total_Hipertensao_Controlada / populacao_media`:
! longer object length is not a multiple of shorter object length
hipertensao_total_2015 <- hipertensao_tempo_all %>%
group_by(distritos.x) %>%
summarise(Taxa_Hipertensao_Controlada = sum(Taxa_Hipertensao_Controlada, na.rm = TRUE)) %>%
arrange(desc(Taxa_Hipertensao_Controlada))%>%
rename(Distrito = distritos.x)
avc_hipertensao_all <- avc_regiao_tempo %>%
inner_join(hipertensao_total_2015, by = "Distrito")
ggplot(avc_hipertensao_all, aes(x = Taxa_Hipertensao_Controlada, y = Taxa_AVC)) +
geom_point(color = "steelblue", size = 3) +
geom_smooth(method = "lm", se = FALSE, color = "red") +
labs(title = "Correlation between Controlled Hypertension Rate and Stroke Rate by District",
x = "Controlled Hypertension Rate from 2015 to 2024",
y = "Stroke Rate from 2022 to 2024") +
theme_minimal()
`geom_smooth()` using formula = 'y ~ x'

correlacao <- cor(avc_hipertensao_all$Taxa_Hipertensao_Controlada, avc_hipertensao_all$Taxa_AVC)
print(correlacao)
[1] -0.1876239
#Testes não paramétricos
#correlação de spearman - monótona não linear
c <- cor(avc_hipertensao_all$Taxa_Hipertensao_Controlada, avc_hipertensao_all$Taxa_AVC, method = "spearman")
print(c)
[1] -0.1545749
# medida não paramétrica que avalia a associação monotônica entre duas variáveis. Ou seja, verifica se, à medida que uma variável aumenta, a outra tende a aumentar (ou diminuir), sem exigir uma relação linear.
#existe uma correlação neagtiva fraca (-0.2125704) entre as duas variáveis
#coreelação de kendall - mede a força e a direção da relação monotônica
k <- cor(avc_hipertensao_all$Taxa_Hipertensao_Controlada, avc_hipertensao_all$Taxa_AVC, method = "kendall")
print(k)
[1] -0.1179419
resultado <- cor.test(avc_hipertensao_all$Taxa_Hipertensao_Controlada, avc_hipertensao_all$Taxa_AVC,
method = "kendall")
print(resultado)
Kendall's rank correlation tau
data: avc_hipertensao_all$Taxa_Hipertensao_Controlada and avc_hipertensao_all$Taxa_AVC
z = -3.7095, p-value = 0.0002077
alternative hypothesis: true tau is not equal to 0
sample estimates:
tau
-0.1179419
#existe uma correlação negativa fraca (-0.1589298) entre as duas variáveis
# 1.72e-06 < 0,05: A correlação é estatisticamente significativa, embora fraca.
#correlação AVC e hipertensão SÓ nos anos em comum
avc_hipertensao <- avc_regiao %>%
inner_join(hipertensao_total, by = "Distrito")
ggplot(avc_hipertensao, aes(x = Total_Hipertensao_Controlada, y = Total_AVC)) +
geom_point(color = "steelblue", size = 3) +
geom_smooth(method = "lm", se = FALSE, color = "red") +
labs(title = "Correlação entre Hipertensão Controlada e Registos de AVC por Distrito",
x = "Total de Hipertensos Controlados",
y = "Total de Registos de AVC") +
theme_minimal()
`geom_smooth()` using formula = 'y ~ x'

correlacao <- cor(avc_hipertensao$Total_Hipertensao_Controlada, avc_hipertensao$Total_AVC)
print(correlacao)
[1] 0.9733902
```
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKYGBge3J9CgojIExpc3RhIGRlIHBhY290ZXMgbmVjZXNzw6FyaW9zCnBhY2thZ2VzIDwtIGMoCiAgImRwbHlyIiwgImdncGxvdDIiLCAiY29ycnBsb3QiLCAiY2FyIiwgImx1YnJpZGF0ZSIsCiAgInRpZHlyIiwgInN0cmluZ3IiLCAic3RyaW5naSIsICJyc3RhdGl4IiwgInNmIiwKICAicHVycnIiLCAiR0dhbGx5IiwgIkZhY3RvTWluZVIiLCAiZmFjdG9leHRyYSIsCiAgInBhdGNod29yayIsICJtaWNlIiwgImphbml0b3IiLCAic2NhbGVzIiwgInRyZW5kIgopCgojIEluc3RhbGFyIGFwZW5hcyBvcyBxdWUgbsOjbyBlc3TDo28gaW5zdGFsYWRvcwppbnN0YWxsZWQgPC0gcGFja2FnZXMgJWluJSByb3duYW1lcyhpbnN0YWxsZWQucGFja2FnZXMoKSkKaWYgKGFueSghaW5zdGFsbGVkKSkgewogIGluc3RhbGwucGFja2FnZXMocGFja2FnZXNbIWluc3RhbGxlZF0pCn0KCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShjb3JycGxvdCkKbGlicmFyeShjYXIpCmxpYnJhcnkobHVicmlkYXRlKQpsaWJyYXJ5KHRpZHlyKQpsaWJyYXJ5KHN0cmluZ3IpCmxpYnJhcnkoc3RyaW5naSkKbGlicmFyeShyc3RhdGl4KQpsaWJyYXJ5KHNmKQpsaWJyYXJ5KHB1cnJyKQpsaWJyYXJ5KEdHYWxseSkKbGlicmFyeShGYWN0b01pbmVSKQpsaWJyYXJ5KGZhY3RvZXh0cmEpCmxpYnJhcnkocGF0Y2h3b3JrKQpsaWJyYXJ5KG1pY2UpCmxpYnJhcnkoamFuaXRvcikKbGlicmFyeShzY2FsZXMpCmxpYnJhcnkodHJlbmQpCgojbGVyIGRhdGEKaHlwZXJ0ZW5zaW9uIDwtIHJlYWQuY3N2MigiaHR0cHM6Ly90cmFuc3BhcmVuY2lhLnNucy5nb3YucHQvYXBpL2V4cGxvcmUvdjIuMS9jYXRhbG9nL2RhdGFzZXRzL2hpcGVydGVuc2FvL2V4cG9ydHMvY3N2P2xhbmc9cHQmdGltZXpvbmU9RXVyb3BlJTJGTGlzYm9uIikKYXZjIDwtIHJlYWQuY3N2MigiaHR0cHM6Ly90cmFuc3BhcmVuY2lhLnNucy5nb3YucHQvYXBpL2V4cGxvcmUvdjIuMS9jYXRhbG9nL2RhdGFzZXRzL2V2b2x1Y2FvLXNpdHVhY29lcy1kb2VudGVzLXNpbmFpcy1zaW50b21hcy1kZS1hdmMvZXhwb3J0cy9jc3Y/bGFuZz1wdCZ0aW1lem9uZT1FdXJvcGUlMkZMb25kb24mdXNlX2xhYmVscz10cnVlJmRlbGltaXRlcj0lM0IiKQoKIyMgVmFtb3MgcHJpbWVpcm8gYW5hbGlzYXIgbyBkYXRhc2V0IGh5cGVydGVuc2lvbjoKCiNWZXIgbWlzc2luZyB2YWx1ZXMgCgpvdXQgPC0gc2FwcGx5KGh5cGVydGVuc2lvbiwgZnVuY3Rpb24oeCkgc3VtKGlzLm5hKHgpIHwgeCA9PSAiIikpCiAgICAgICAKI25vIGRhdGFmcmFtZSBkZSBoaXBlcnRlbnPDo28gZXhpc3RlbSAyNCBtaXNzaW5nIHZhbHVlcyBuYSB2YXJpYXZlbCBwb250b19vdV9sb2NhbGl6YWNhb19nZW9ncmFmaWNhLgojUmV0aXJvIGFzIG9ic2VydmHDp8O1ZXMgb3UgZmHDp28gaW1wdXRhw6fDo28/IFRlbmhvIGRlIHZlciBzZSDDqSByZWxldmFudGUgdGFtYsOpbQoKCiNhdmFsaWFyIHJlbGV2w6JuY2lhIGRhIHZhcmnDoXZlbAojdmVyIHJlbGV2w6JuY2lhIGRhIGxvY2FsaXphw6fDo28gcGFyYSBvcyB2YWxvcmVzIGRlIGhpcGVydGVuw6fDo28KIyBNb2RlbG8gY29tcGxldG8gLSByZWdyZXNzw6NvIGRlIHBvaXNzb24gKHZhcmnDoXZlbCDDqSB1bWEgY29udGFnZW0pCm1vZGVsb19jb21wbGV0byA8LSBnbG0oY29udGFnZW1fZGVfdXRlbnRlc19pbnNjcml0b3NfY29tX2hpcGVydGVuc2FvX2FydGVyaWFsX2NvbV9wcmVzc2FvX2FydGVyaWFsX2luZmVyaW9yX2FfMTUwXzkwX21taGdfbiB+IAogICAgcG9udG9fb3VfbG9jYWxpemFjYW9fZ2VvZ3JhZmljYSArIHJlZ2lhbyArIHRlbXBvLCBkYXRhID0gaHlwZXJ0ZW5zaW9uKQoKIyBNb2RlbG8gc2VtIHBvbnRvX291X2xvY2FsaXphY2FvX2dlb2dyYWZpY2EKbW9kZWxvX3JlZHV6aWRvIDwtIGdsbShjb250YWdlbV9kZV91dGVudGVzX2luc2NyaXRvc19jb21faGlwZXJ0ZW5zYW9fYXJ0ZXJpYWxfY29tX3ByZXNzYW9fYXJ0ZXJpYWxfaW5mZXJpb3JfYV8xNTBfOTBfbW1oZ19uIH4gCiAgICByZWdpYW8gKyB0ZW1wbywgZGF0YSA9IGh5cGVydGVuc2lvbikKCiMgVGVzdGUgZGUgcmF6w6NvIGRlIHZlcm9zc2ltaWxoYW7Dp2EKYW5vdmEobW9kZWxvX3JlZHV6aWRvLCBtb2RlbG9fY29tcGxldG8sIHRlc3QgPSAiQ2hpc3EiKQojdmFyacOhdmVsIHJlbGV2YW50ZQoKCnRvdGFsX2RhdGEgPC0gIGxlbmd0aChoeXBlcnRlbnNpb24kcG9udG9fb3VfbG9jYWxpemFjYW9fZ2VvZ3JhZmljYSkKcGVyY2VudGFnZV9udWxsIDwtIDEwMCphcy5udW1lcmljKG91dFsicG9udG9fb3VfbG9jYWxpemFjYW9fZ2VvZ3JhZmljYSJdKS90b3RhbF9kYXRhCgojcGVyY2VudGFnZW0gZGUgbWlzc2luZyB2YWx1ZXMgw6kgMC4zNjU5IC0gbXVpdG8gcGVxdWVuYSBsb2dvIGVtIHByaW5jw61waW8gcG9kZSBzZXIgYWNlaXTDoXZlbCByZW1vdmUtbGFzCgoKI3ZlciBkaXN0cmlidWnDp8OjbyB0ZW1wb3JhbCBkb3MgdmFsb3JlcyBzZW0gbG9jYWxpemHDp8OjbyBjb3JyZXNwb25kZW50ZSBlIHJlc3BldGl2YSBwZXJjZW50YWdlbQp3aGVyZV9uYSA8LSBoeXBlcnRlbnNpb24gJT4lCiAgZmlsdGVyKHBvbnRvX291X2xvY2FsaXphY2FvX2dlb2dyYWZpY2EgPT0gIiIgfCBpcy5uYSAocG9udG9fb3VfbG9jYWxpemFjYW9fZ2VvZ3JhZmljYSkpICU+JQogIGNvdW50KHRlbXBvLCBuYW1lID0gImF1c2VudGVzIikKCnRvdGFsX3BlcmlvZCA8LSBoeXBlcnRlbnNpb24gJT4lCiAgY291bnQodGVtcG8sIG5hbWUgPSAidG90YWwiKQoKcGVyY2VudGFnZXMgPC0gbGVmdF9qb2luKHdoZXJlX25hLCB0b3RhbF9wZXJpb2QsIGJ5ID0gInRlbXBvIikgJT4lCiAgbXV0YXRlKHBlcmNlbnRhZ2VtID0gcm91bmQoKGF1c2VudGVzIC8gdG90YWwpICogMTAwLCAyKSkKCiNhIHBlcmNlbnRhZ2VtIHNvYmUgNS4xMyUgLCBjcmlhbmRvIGR1dmlkYXMgc29icmUgYSByZW1vw6fDo28KCiNjb21wb3J0YW1lbnRvIGRvcyB2YWxvcmVzIHNlbSBsb2NhbGl6YcOnw6NvIGNvcnJlc3BvbmRlbnRlCiMgQWRpY2lvbmEgdW1hIGZsYWcgcGFyYSBtaXNzaW5nIG91IG7Do28KaHlwZXJ0ZW5zaW9uJGxvY2FsaXphY2FvIDwtIGlmZWxzZShoeXBlcnRlbnNpb24kcG9udG9fb3VfbG9jYWxpemFjYW9fZ2VvZ3JhZmljYSA9PSAiIiB8IGlzLm5hKGh5cGVydGVuc2lvbiRwb250b19vdV9sb2NhbGl6YWNhb19nZW9ncmFmaWNhKSwgRkFMU0UsIFRSVUUpCgojIENvbXBhcmEgYXMgbcOpZGlhcyBlIG1lZGlhbmFzCiMgdG90YWwgZGUgZGFkb3MKbWV0cmljYV90b3RhbCA8LSBoeXBlcnRlbnNpb24gJT4lCiAgICAgc3VtbWFyaXNlKGFjcm9zcyh3aGVyZShpcy5udW1lcmljKSwgbGlzdChtZWRpYSA9IG1lYW4sIG1lZGlhbmEgPSBtZWRpYW4sIHZhcmlhbmNpYSA9IHZhciksIG5hLnJtID0gVFJVRSkpCiAKIyBkYWRvcyBjb20gbG9jYWxpemHDp8OjbwptZXRyaWNhX2NvbV9sb2NhbCA8LSBoeXBlcnRlbnNpb24gJT4lCiAgICAgZmlsdGVyKGxvY2FsaXphY2FvICE9IEZBTFNFKSAlPiUKICAgICBzdW1tYXJpc2UoYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpLCBsaXN0KG1lZGlhID0gbWVhbiwgbWVkaWFuYSA9IG1lZGlhbiwgdmFyaWFuY2lhID0gdmFyKSwgbmEucm0gPSBUUlVFKSkKCiNvcyB2YWxvcmVzIGRhcyBtw6l0cmljYXMgY29tcGFyYWRhcyBuw6NvIHPDo28gbXVpdG8gZGlzY3JlcGFudGVzIGxvZ28gY29uY2x1aW1vcyBxdWUgYSBtZWxob3IgYWJvcmRhZ2VtIMOpIGEgaW1wdXRhw6fDo28gcG9ycXVlIG9zIGRhZG9zIHNlbSBsb2NhbGl6YcOnw6NvIHJlcHJlc2VudGFtIGEgYW1vc3RyYSwgYSBxdWUgw6kgY29uZmlybWFkbyBwZWxvIFdlbGNoIFR3byBTYW1wbGUgdC10ZXN0CmFtb3N0cmExIDwtIGh5cGVydGVuc2lvbiRjb250YWdlbV9kZV91dGVudGVzX2luc2NyaXRvc19jb21faGlwZXJ0ZW5zYW9fYXJ0ZXJpYWxfY29tX3ByZXNzYW9fYXJ0ZXJpYWxfaW5mZXJpb3JfYV8xNTBfOTBfbW1oZ19uCmFtb3N0cmEyIDwtIGh5cGVydGVuc2lvbiAlPiUKICBmaWx0ZXIobG9jYWxpemFjYW8gIT0gRkFMU0UpICU+JQogIHB1bGwoY29udGFnZW1fZGVfdXRlbnRlc19pbnNjcml0b3NfY29tX2hpcGVydGVuc2FvX2FydGVyaWFsX2NvbV9wcmVzc2FvX2FydGVyaWFsX2luZmVyaW9yX2FfMTUwXzkwX21taGdfbikKCnQudGVzdChhbW9zdHJhMSwgYW1vc3RyYTIsIHZhci5lcXVhbCA9IEZBTFNFKQoKIyBwLXZhbHVlPSAwLjY0NjMgPiAwLjA1ICwgbsOjbyByZWplaXRhbW9zIGEgaGlwb3Rlc2UgbnVsYS4gQ29uY2x1w61tb3MgcXVlIG7Do28gaMOhIGRpZmVyZW7Dp2Egc2lnbmlmaWNhdGl2YSBlbnRyZSBhcyBtw6lkaWFzLgpgYGAKCmBgYHtyfQojIHRvcm5hciBpbmRleCBkYSBsb2NhbGl6YcOnw6NvIG1haXMgYWNlc3NpdmVsIHBhcmEgcXVlIGEgaW1wdXRhw6fDo28gcG9zc2EgZmF6ZXIgbWFpcyBzZW50aWRvCiMgUmVub21lYXIgYSBjb2x1bmEgZGUgY29vcmRlbmFkYXMKaHlwZXJ0ZW5zaW9uIDwtIGh5cGVydGVuc2lvbiAlPiUKICByZW5hbWUoY29vcmRzID0gcG9udG9fb3VfbG9jYWxpemFjYW9fZ2VvZ3JhZmljYSkKCiMgU2VwYXJhciBjb29yZGVuYWRhcyBlbSBsYXQvbG9uCiMgU2VwYXJhciBhIGNvbHVuYSBkZSBjb29yZGVuYWRhcyBlbSBsYXRpdHVkZSBlIGxvbmdpdHVkZQoKaHlwX2Nvb3JkcyA8LSBoeXBlcnRlbnNpb24gJT4lCiAgc2VwYXJhdGUoY29vcmRzLCBpbnRvID0gYygibGF0IiwgImxvbiIpLCBzZXAgPSAiLCIsIGNvbnZlcnQgPSBUUlVFKSAlPiUKICBtdXRhdGUoCiAgICBsYXQgPSBhcy5udW1lcmljKHN0cl9yZXBsYWNlKGxhdCwgIiwiLCAiLiIpKSwKICAgIGxvbiA9IGFzLm51bWVyaWMoc3RyX3JlcGxhY2UobG9uLCAiLCIsICIuIikpLAogICAgcHJvcG9yY2FvX2hpcGVydGVuc29zXzY1X2FfY29tX3BhXzE1MF85MCA9IGFzLm51bWVyaWMocHJvcG9yY2FvX2hpcGVydGVuc29zXzY1X2FfY29tX3BhXzE1MF85MCkKICApCgojIEdhcmFudGlyIHF1ZSBhIHByb3BvcsOnw6NvIGVzdGVqYSBlbSBmb3JtYXRvIG51bcOpcmljbwpoeXBfY29vcmRzIDwtIGh5cF9jb29yZHMgJT4lCiAgbXV0YXRlKHByb3BvcmNhb19oaXBlcnRlbnNvc182NV9hX2NvbV9wYV8xNTBfOTAgPSBhcy5udW1lcmljKHByb3BvcmNhb19oaXBlcnRlbnNvc182NV9hX2NvbV9wYV8xNTBfOTApKQoKCiMgQ29udmVydGVyIHBhcmEgc2YKaHlwX3NmIDwtIGh5cF9jb29yZHMgJT4lCiAgbXV0YXRlKGdlb21ldHJ5ID0gcG1hcChsaXN0KGxvbiwgbGF0KSwgZnVuY3Rpb24oeCwgeSkgewogICAgaWYgKGlzLm5hKHgpIHx8IGlzLm5hKHkpKSB7CiAgICAgIHN0X2dlb21ldHJ5Y29sbGVjdGlvbigpCiAgICB9IGVsc2UgewogICAgICBzdF9wb2ludChjKHgsIHkpKQogICAgfQogIH0pKSAlPiUKICBzdF9hc19zZihjcnMgPSA0MzI2KQojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KIyA0LiBDYXJyZWdhciBzaGFwZWZpbGVzIChuw612ZWlzIDIpCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKIyBNdW5pY8OtcGlvcyAoTsOtdmVsIDIpCm11bmljaXBpb3MgPC0gc3RfcmVhZCgiZ2FkbTQxX1BSVF8yLnNocCIpICU+JSBzdF90cmFuc2Zvcm0oNDMyNikKbXVuaWNpcGlvcyA8LSBtdW5pY2lwaW9zICU+JQogIHJlbmFtZShkaXN0cml0b3MgPSBOQU1FXzEsCiAgICAgICAgIG11bmljaXBpbyA9IE5BTUVfMikKCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQojIDUuIEpvaW4gZXNwYWNpYWw6IEhpcGVydGVuc8OjbyDihpIgTXVuaWPDrXBpbwojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCmh5cGVyX2pvaW5lZCA8LSBzdF9qb2luKGh5cF9zZiwgbXVuaWNpcGlvcywgam9pbiA9IHN0X3dpdGhpbikKCmBgYAoKYGBge3J9CiNpbXB1dGFjYW8gY29tIGJhc2UgbmEgc2VtZWxoYW7Dp2EgZGUgdmFsb3JlcwoKIyBDYWxjdWxhciBhIG3DqWRpYSBwb3IgZ3J1cG8gbXVuaWNpcGlvCm1lYW5fcGVyX2dyb3VwIDwtIGh5cGVyX2pvaW5lZCAlPiUKICBmaWx0ZXIoIWlzLm5hKG11bmljaXBpbykpICU+JQogIGdyb3VwX2J5KG11bmljaXBpbykgJT4lCiAgc3VtbWFyaXNlKG1lYW5fY29udGFnZW0gPSBtZWFuKGNvbnRhZ2VtX2RlX3V0ZW50ZXNfaW5zY3JpdG9zX2NvbV9oaXBlcnRlbnNhb19hcnRlcmlhbF9jb21fcHJlc3Nhb19hcnRlcmlhbF9pbmZlcmlvcl9hXzE1MF85MF9tbWhnX24sIG5hLnJtID0gVFJVRSkpICU+JQogIHN0X3NldF9nZW9tZXRyeShOVUxMKQoKZGVzdmlvIDwtIGh5cGVyX2pvaW5lZCAlPiUKICBmaWx0ZXIoIWlzLm5hKG11bmljaXBpbykpICU+JQogIGdyb3VwX2J5KG11bmljaXBpbykgJT4lCiAgc3VtbWFyaXNlKGRlc3Zpb19jb250YWdlbSA9IHNkKGNvbnRhZ2VtX2RlX3V0ZW50ZXNfaW5zY3JpdG9zX2NvbV9oaXBlcnRlbnNhb19hcnRlcmlhbF9jb21fcHJlc3Nhb19hcnRlcmlhbF9pbmZlcmlvcl9hXzE1MF85MF9tbWhnX24sIG5hLnJtID0gRkFMU0UpKSAlPiUKICBzdF9zZXRfZ2VvbWV0cnkoTlVMTCkKCgppbnRlcnZhbG8gPC0gbWVhbl9wZXJfZ3JvdXAgJT4lCiAgbGVmdF9qb2luKGRlc3ZpbywgYnkgPSAibXVuaWNpcGlvIikgJT4lCiAgbXV0YXRlKAogICAgbGltaXRlX2luZmVyaW9yID0gbWVhbl9jb250YWdlbSAtIGRlc3Zpb19jb250YWdlbSwKICAgIGxpbWl0ZV9zdXBlcmlvciA9IG1lYW5fY29udGFnZW0gKyBkZXN2aW9fY29udGFnZW0KICApCgojIEltcHV0YXIgbXVuaWNpcGlvIGNvbSBiYXNlIG5hIG3DqWRpYSBtYWlzIHByw7N4aW1hIGRhIGNvbnRhZ2VtCmh5cF9maW5hbCA8LSBoeXBlcl9qb2luZWQgJT4lCiAgcm93d2lzZSgpICU+JQogIG11dGF0ZShtdW5pY2lwaW8gPSBpZl9lbHNlKAogICAgaXMubmEobXVuaWNpcGlvKSwKICAgIHsKICAgICAgY29udF92YWwgPC0gY29udGFnZW1fZGVfdXRlbnRlc19pbnNjcml0b3NfY29tX2hpcGVydGVuc2FvX2FydGVyaWFsX2NvbV9wcmVzc2FvX2FydGVyaWFsX2luZmVyaW9yX2FfMTUwXzkwX21taGdfbgogICAgICAKICAgICAgIyBWZXJpZmljYSBxdWFpcyBtdW5pY8OtcGlvcyB0w6ptIG8gdmFsb3IgZGVudHJvIGRvIGludGVydmFsbwogICAgICBkZW50cm9faW50ZXJ2YWxvIDwtIGludGVydmFsbyAlPiUKICAgICAgICBmaWx0ZXIoY29udF92YWwgPj0gbGltaXRlX2luZmVyaW9yICYgY29udF92YWwgPD0gbGltaXRlX3N1cGVyaW9yKQoKICAgICAgaWYgKG5yb3coZGVudHJvX2ludGVydmFsbykgPiAwKSB7CiAgICAgICAgIyBFbnRyZSBvcyB2w6FsaWRvcywgcGVnYSBvIGRlIG3DqWRpYSBtYWlzIHByw7N4aW1hCiAgICAgICAgZGlmZnMgPC0gYWJzKGRlbnRyb19pbnRlcnZhbG8kbWVhbl9jb250YWdlbSAtIGNvbnRfdmFsKQogICAgICAgIGRlbnRyb19pbnRlcnZhbG8kbXVuaWNpcGlvW3doaWNoLm1pbihkaWZmcyldCiAgICAgIH0gZWxzZSB7CiAgICAgICAgTkFfY2hhcmFjdGVyXwogICAgICB9CiAgICB9LAogICAgbXVuaWNpcGlvCiAgKSkgJT4lCiAgdW5ncm91cCgpJT4lCiAgZmlsdGVyKCFpcy5uYShtdW5pY2lwaW8pKQoKCgp0YWJlbGFfY29ycmVzcG9uZGVuY2lhIDwtIG11bmljaXBpb3MgJT4lCiAgc3RfZHJvcF9nZW9tZXRyeSgpICU+JQogIHNlbGVjdChkaXN0cml0b3MsIG11bmljaXBpbykgJT4lCiAgZGlzdGluY3QoKQoKaHlwX2ZpbmFsIDwtIGh5cF9maW5hbCAlPiUKICBtdXRhdGUobXVuaWNpcGlvX2NsZWFuID0gc3RyaV90cmFuc19nZW5lcmFsKHRvbG93ZXIodHJpbXdzKG11bmljaXBpbykpLCAiTGF0aW4tQVNDSUkiKSkKCnRhYmVsYV9jb3JyZXNwb25kZW5jaWEgPC0gdGFiZWxhX2NvcnJlc3BvbmRlbmNpYSAlPiUKICBtdXRhdGUobXVuaWNpcGlvX2NsZWFuID0gc3RyaV90cmFuc19nZW5lcmFsKHRvbG93ZXIodHJpbXdzKG11bmljaXBpbykpLCAiTGF0aW4tQVNDSUkiKSkKCiMgMi4gRmF6IG8gam9pbiBjb20gYmFzZSBuYSB2ZXJzw6NvIGxpbXBhCmh5cF9maW5hbCA8LSBoeXBfZmluYWwgJT4lCiAgbGVmdF9qb2luKHRhYmVsYV9jb3JyZXNwb25kZW5jaWEgJT4lIHNlbGVjdChtdW5pY2lwaW9fY2xlYW4sIGRpc3RyaXRvcyksIGJ5ID0gIm11bmljaXBpb19jbGVhbiIpCmBgYAoKYGBge3J9CgojIC0tLSBFZmVpdG8gZGEgaW1wdXRhw6fDo28gbmEgbcOpZGlhIC0tLQojIDEuIE3DqWRpYSBvcmlnaW5hbCBwb3IgZ3J1cG8KbWVhbl9hdHRyIDwtIGh5cGVyX2pvaW5lZCAlPiUKICBmaWx0ZXIoIWlzLm5hKG11bmljaXBpbykpICU+JQogIGdyb3VwX2J5KG11bmljaXBpbykgJT4lCiAgc3VtbWFyaXNlKG1lYW5fb3JpZ2luYWwgPSBtZWFuKGNvbnRhZ2VtX2RlX3V0ZW50ZXNfaW5zY3JpdG9zX2NvbV9oaXBlcnRlbnNhb19hcnRlcmlhbF9jb21fcHJlc3Nhb19hcnRlcmlhbF9pbmZlcmlvcl9hXzE1MF85MF9tbWhnX24sIG5hLnJtID0gVFJVRSkpICU+JQogIHN0X3NldF9nZW9tZXRyeShOVUxMKQoKIyAyLiBNw6lkaWEgYXDDs3MgaW1wdXRhw6fDo28gKGVtIGh5cF9maW5hbCkKbWVhbl9wZXJfZ3JvdXBfY29tX2ltcCA8LSBoeXBfZmluYWwgJT4lCiAgZ3JvdXBfYnkobXVuaWNpcGlvKSAlPiUKICBzdW1tYXJpc2UobWVhbl9pbXB1dGFkYSA9IG1lYW4oY29udGFnZW1fZGVfdXRlbnRlc19pbnNjcml0b3NfY29tX2hpcGVydGVuc2FvX2FydGVyaWFsX2NvbV9wcmVzc2FvX2FydGVyaWFsX2luZmVyaW9yX2FfMTUwXzkwX21taGdfbiwgbmEucm0gPSBUUlVFKSkgJT4lCiAgc3Rfc2V0X2dlb21ldHJ5KE5VTEwpCgojIDMuIEp1bnRhciBtw6lkaWFzIG9yaWdpbmFsIGUgaW1wdXRhZGEKbWVhbnMgPC0gbGVmdF9qb2luKG1lYW5fYXR0ciwgbWVhbl9wZXJfZ3JvdXBfY29tX2ltcCwgYnkgPSAibXVuaWNpcGlvIikKCiMgNC4gR3LDoWZpY28gZGFzIG3DqWRpYXMKbWVhbnNfbG9uZyA8LSBtZWFucyAlPiUKICBwaXZvdF9sb25nZXIoY29scyA9IGMobWVhbl9vcmlnaW5hbCwgbWVhbl9pbXB1dGFkYSksCiAgICAgICAgICAgICAgIG5hbWVzX3RvID0gInRpcG9fbWVkaWEiLAogICAgICAgICAgICAgICB2YWx1ZXNfdG8gPSAibWVkaWEiKQoKZ3JhZmljbyA8LSBnZ3Bsb3QobWVhbnNfbG9uZywgYWVzKHggPSBtdW5pY2lwaW8sIHkgPSBtZWRpYSwgZmlsbCA9IHRpcG9fbWVkaWEpKSArCiAgZ2VvbV9jb2wocG9zaXRpb24gPSAiZG9kZ2UiKSArCiAgbGFicyh0aXRsZSA9ICJDb21wYXJhw6fDo28gZGFzIG3DqWRpYXMgcG9yIG11bmljaXBpbyIsCiAgICAgICB4ID0gIk11bmljaXBpbyIsIHkgPSAiTcOpZGlhIGRhIGNvbnRhZ2VtIiwKICAgICAgIGZpbGwgPSAiVGlwbyBkZSBNw6lkaWEiKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKQoKZ2dzYXZlKGZpbGVuYW1lID0gImdyYWZpY29fbWVkaWFzX3Bvcl9ncnVwby5wbmciLCBwbG90ID0gZ3JhZmljbywgd2lkdGggPSAxMCwgaGVpZ2h0ID0gNiwgZHBpID0gMzAwKQoKCiMgNS4gRGlzdMOibmNpYSBlbnRyZSB2YWxvciBpbXB1dGFkbyBlIG3DqWRpYSBvcmlnaW5hbCBkbyBncnVwbwpkaXN0YW5jZSA8LSBoeXBfZmluYWwgJT4lCiAgZmlsdGVyKGxvY2FsaXphY2FvID09IEZBTFNFKSAlPiUKICBzdF9zZXRfZ2VvbWV0cnkoTlVMTCkgJT4lCiAgbGVmdF9qb2luKG1lYW5fYXR0ciwgYnkgPSAibXVuaWNpcGlvIikgJT4lCiAgbXV0YXRlKGRpc3QgPSBtZWFuX29yaWdpbmFsIC0gY29udGFnZW1fZGVfdXRlbnRlc19pbnNjcml0b3NfY29tX2hpcGVydGVuc2FvX2FydGVyaWFsX2NvbV9wcmVzc2FvX2FydGVyaWFsX2luZmVyaW9yX2FfMTUwXzkwX21taGdfbikKCiMgNi4gR3LDoWZpY28gZGUgbGluaGFzIHBhcmEgYW5hbGlzYXIgNS4KIyBDcmlhciBsaW1pdGVzIHBhcmEgYSByZWdpw6NvIHNvbWJyZWFkYSAoYmFuZGEgZGUgY29uZmlhbsOnYSkKZGlzdGFuY2UgPC0gZGlzdGFuY2UgJT4lCiAgbXV0YXRlKAogICAgeW1pbiA9IG1lYW5fb3JpZ2luYWwgLSBhYnMoZGlzdCksCiAgICB5bWF4ID0gbWVhbl9vcmlnaW5hbCArIGFicyhkaXN0KQogICkKCmdyYWZpY29fMiA8LSBnZ3Bsb3QoZGlzdGFuY2UsIGFlcyh4ID0gcmVvcmRlcihtdW5pY2lwaW8sIG1lYW5fb3JpZ2luYWwpLCB5ID0gbWVhbl9vcmlnaW5hbCwgZ3JvdXAgPSAxKSkgKwogIGdlb21fcmliYm9uKGFlcyh5bWluID0geW1pbiwgeW1heCA9IHltYXgpLCBmaWxsID0gImxpZ2h0Ymx1ZSIsIGFscGhhID0gMC40KSArICAjIHJlZ2nDo28gc29tYnJlYWRhCiAgZ2VvbV9saW5lKGNvbG9yID0gImJsdWUiLCBzaXplID0gMSkgKyAgIyBsaW5oYSBkYSBtw6lkaWEKICBnZW9tX3BvaW50KGFlcyh5ID0gY29udGFnZW1fZGVfdXRlbnRlc19pbnNjcml0b3NfY29tX2hpcGVydGVuc2FvX2FydGVyaWFsX2NvbV9wcmVzc2FvX2FydGVyaWFsX2luZmVyaW9yX2FfMTUwXzkwX21taGdfbiksCiAgICAgICAgICAgICBjb2xvciA9ICJyZWQiLCBzaXplID0gMikgKyAgIyBwb250b3MgZG8gdmFsb3IgaW1wdXRhZG8KICBsYWJzKAogICAgeCA9ICJNdW5pY8OtcGlvcyBjb20gdmFsb3JlcyBpbXB1dGFkb3MiLAogICAgeSA9ICJWYWxvciIsCiAgICB0aXRsZSA9ICJNw6lkaWEgb3JpZ2luYWwgdnMgZGlzdMOibmNpYSBkbyB2YWxvciBpbXB1dGFkbyIsCiAgICBzdWJ0aXRsZSA9ICJMaW5oYSBhenVsOiBtw6lkaWEgb3JpZ2luYWw7IFJlZ2nDo28gYXp1bCBjbGFyYTogZGlzdMOibmNpYTsgUG9udG9zIHZlcm1lbGhvczogdmFsb3JlcyBpbXB1dGFkb3MiCiAgKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZSgKICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkKICApCgpnZ3NhdmUoZmlsZW5hbWUgPSAiZ3JhZmljb19kaXN0YW5jaWFzX3Bvcl9ncnVwby5wbmciLCBwbG90ID0gZ3JhZmljb18yLCB3aWR0aCA9IDEwLCBoZWlnaHQgPSA2LCBkcGkgPSAzMDApCgojIC0tLSBDb21wYXJhw6fDo28gZGEgZGlzdHJpYnVpw6fDo28gcmVnaW9uYWw6IGltcHV0YWRvcyB2cyByZWFpcyAtLS0KdGFiZWxhX2NvbXBhcmF0aXZhIDwtIGh5cF9maW5hbCAlPiUKICBtdXRhdGUodGlwbyA9IGlmZWxzZShsb2NhbGl6YWNhbywgIlJlYWwiLCAiSW1wdXRhZG8iKSkgJT4lCiAgZ3JvdXBfYnkobXVuaWNpcGlvLCB0aXBvKSAlPiUKICBzdW1tYXJpc2UodG90YWwgPSBuKCksIC5ncm91cHMgPSAiZHJvcCIpICU+JQogIGdyb3VwX2J5KHRpcG8pICU+JQogIG11dGF0ZShwcm9wID0gdG90YWwgLyBzdW0odG90YWwpKQoKcCA8LSBnZ3Bsb3QodGFiZWxhX2NvbXBhcmF0aXZhLCBhZXMoeCA9IHByb3AsIHkgPSBtdW5pY2lwaW8sIGZpbGwgPSB0aXBvKSkgKwogIGdlb21fY29sKHBvc2l0aW9uID0gImRvZGdlIikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgbGFicyh0aXRsZSA9ICJEaXN0cmlidWnDp8OjbyBkZSBNdW5pY8OtcGlvczogUmVhbCB2cyBJbXB1dGFkbyIsCiAgICAgICB5ID0gIk11bmljw61waW8iLCB4ID0gIlByb3BvcsOnw6NvIikgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0ID0gMC41LCBoanVzdCA9IDEpKQoKZ2dzYXZlKCJncmFmaWNvX2Rpc3RyaWJ1aWNhby5wbmciLCBwbG90ID0gcCwgd2lkdGggPSAxMCwgaGVpZ2h0ID0gOCwgZHBpID0gMzAwKQoKIyAtLS0gQ29ycmVsYcOnw6NvIC0tLQpjb3JfYmVmb3JlIDwtIGNvcigKICBoeXBlcl9qb2luZWQkY29udGFnZW1fZGVfdXRlbnRlc19pbnNjcml0b3NfY29tX2hpcGVydGVuc2FvX2FydGVyaWFsX2NvbV9wcmVzc2FvX2FydGVyaWFsX2luZmVyaW9yX2FfMTUwXzkwX21taGdfbiwKICBoeXBlcl9qb2luZWQkcHJvcG9yY2FvX2hpcGVydGVuc29zXzY1X2FfY29tX3BhXzE1MF85MCwKICB1c2UgPSAiY29tcGxldGUub2JzIgopCgpjb3JfYWZ0ZXIgPC0gY29yKAogIGh5cF9maW5hbCRjb250YWdlbV9kZV91dGVudGVzX2luc2NyaXRvc19jb21faGlwZXJ0ZW5zYW9fYXJ0ZXJpYWxfY29tX3ByZXNzYW9fYXJ0ZXJpYWxfaW5mZXJpb3JfYV8xNTBfOTBfbW1oZ19uLAogIGh5cF9maW5hbCRwcm9wb3JjYW9faGlwZXJ0ZW5zb3NfNjVfYV9jb21fcGFfMTUwXzkwCikKCmNhdCgiQ29ycmVsYcOnw6NvIGFudGVzIGRhIGltcHV0YcOnw6NvOiIsIGNvcl9iZWZvcmUsICJcbiIpCmNhdCgiQ29ycmVsYcOnw6NvIGRlcG9pcyBkYSBpbXB1dGHDp8OjbzoiLCBjb3JfYWZ0ZXIsICJcbiIpCgojc3VtbWFyeQpzdW1tYXJ5KGh5cGVyX2pvaW5lZCAlPiUgc2VsZWN0KGNvbnRhZ2VtX2RlX3V0ZW50ZXNfaW5zY3JpdG9zX2NvbV9oaXBlcnRlbnNhb19hcnRlcmlhbF9jb21fcHJlc3Nhb19hcnRlcmlhbF9pbmZlcmlvcl9hXzE1MF85MF9tbWhnX24sIHByb3BvcmNhb19oaXBlcnRlbnNvc182NV9hX2NvbV9wYV8xNTBfOTApKQpzdW1tYXJ5KGh5cF9maW5hbCAlPiUgc2VsZWN0KGNvbnRhZ2VtX2RlX3V0ZW50ZXNfaW5zY3JpdG9zX2NvbV9oaXBlcnRlbnNhb19hcnRlcmlhbF9jb21fcHJlc3Nhb19hcnRlcmlhbF9pbmZlcmlvcl9hXzE1MF85MF9tbWhnX24sIHByb3BvcmNhb19oaXBlcnRlbnNvc182NV9hX2NvbV9wYV8xNTBfOTApKQoKCiMgLS0tIERpc3BlcnPDo28gZGFzIHZhcmnDoXZlaXMgcHJpbmNpcGFpcyAtLS0KZ2dwbG90KGh5cF9maW5hbCwgYWVzKHggPSBjb250YWdlbV9kZV91dGVudGVzX2luc2NyaXRvc19jb21faGlwZXJ0ZW5zYW9fYXJ0ZXJpYWxfY29tX3ByZXNzYW9fYXJ0ZXJpYWxfaW5mZXJpb3JfYV8xNTBfOTBfbW1oZ19uLAogICAgICAgICAgICAgICAgICAgICAgeSA9IHByb3BvcmNhb19oaXBlcnRlbnNvc182NV9hX2NvbV9wYV8xNTBfOTAsCiAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9IGxvY2FsaXphY2FvKSkgKwogIGdlb21fcG9pbnQoKSArCiAgbGFicyh0aXRsZSA9ICJDb3JyZWxhw6fDo286IFJlYWlzIHZzIEltcHV0YWRvcyIsIGNvbG9yID0gIkRhZG9zIHJlYWlzPyIpCgojIC0tLSBQQ0EgcGFyYSB2aXN1YWxpemHDp8OjbyBtdWx0aXZhcmlhZGEgLS0tCmRhZG9zX3BjYSA8LSBzdF9kcm9wX2dlb21ldHJ5KGh5cF9maW5hbFssIGMoImNvbnRhZ2VtX2RlX3V0ZW50ZXNfaW5zY3JpdG9zX2NvbV9oaXBlcnRlbnNhb19hcnRlcmlhbF9jb21fcHJlc3Nhb19hcnRlcmlhbF9pbmZlcmlvcl9hXzE1MF85MF9tbWhnX24iLCJwcm9wb3JjYW9faGlwZXJ0ZW5zb3NfNjVfYV9jb21fcGFfMTUwXzkwIildKQoKcmVzLnBjYSA8LSBQQ0EoZGFkb3NfcGNhLCBncmFwaCA9IEZBTFNFKQpmdml6X3BjYV9pbmQocmVzLnBjYSwgCiAgICAgICAgICAgICBoYWJpbGxhZ2UgPSBhcy5mYWN0b3IoaHlwX2ZpbmFsJGxvY2FsaXphY2FvKSwKICAgICAgICAgICAgIHRpdGxlID0gIlBDQTogSW1wdXRlZCB2cyBSZWFsIERhdGEiLAogICAgICAgICAgICAgcGFsZXR0ZSA9IGMoInJlZCIsICJibHVlIikpICAjIFZlcm1lbGhvID0gaW1wdXRhZG8sIEF6dWwgPSByZWFsCgoKZ2dwbG90KGh5cGVyX2pvaW5lZCwgYWVzKHggPSBjb250YWdlbV9kZV91dGVudGVzX2luc2NyaXRvc19jb21faGlwZXJ0ZW5zYW9fYXJ0ZXJpYWxfY29tX3ByZXNzYW9fYXJ0ZXJpYWxfaW5mZXJpb3JfYV8xNTBfOTBfbW1oZ19uKSkgKwogIGdlb21faGlzdG9ncmFtKGJpbnMgPSAzMCwgZmlsbCA9ICJibHVlIiwgYWxwaGEgPSAwLjUpICsgZ2d0aXRsZSgiQ29udGFnZW0gQW50ZXMgZGEgSW1wdXRhw6fDo28iKQoKZ2dwbG90KGh5cF9maW5hbCwgYWVzKHggPSBjb250YWdlbV9kZV91dGVudGVzX2luc2NyaXRvc19jb21faGlwZXJ0ZW5zYW9fYXJ0ZXJpYWxfY29tX3ByZXNzYW9fYXJ0ZXJpYWxfaW5mZXJpb3JfYV8xNTBfOTBfbW1oZ19uKSkgKwogIGdlb21faGlzdG9ncmFtKGJpbnMgPSAzMCwgZmlsbCA9ICJncmVlbiIsIGFscGhhID0gMC41KSArIGdndGl0bGUoIkNvbnRhZ2VtIERlcG9pcyBkYSBJbXB1dGHDp8OjbyIpCgpnZ3Bsb3QoaHlwZXJfam9pbmVkLCBhZXMoeCA9IHByb3BvcmNhb19oaXBlcnRlbnNvc182NV9hX2NvbV9wYV8xNTBfOTApKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlucyA9IDMwLCBmaWxsID0gImJsdWUiLCBhbHBoYSA9IDAuNSkgKyBnZ3RpdGxlKCJQcm9wb3LDp8OjbyBBbnRlcyBkYSBJbXB1dGHDp8OjbyIpCgpnZ3Bsb3QoaHlwX2ZpbmFsLCBhZXMoeCA9IHByb3BvcmNhb19oaXBlcnRlbnNvc182NV9hX2NvbV9wYV8xNTBfOTApKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlucyA9IDMwLCBmaWxsID0gImdyZWVuIiwgYWxwaGEgPSAwLjUpICsgZ2d0aXRsZSgiUHJvcG9yw6fDo28gRGVwb2lzIGRhIEltcHV0YcOnw6NvIikKCgoKI2ltcHV0YcOnw6NvIGNvbSBzdWNlc3NvCmBgYAoKYGBge3J9CgojQW5hbGlzZSB0ZW1wb3JhbCBkbyBkYXRhZnJhbWUgZGEgaGlwZXJ0ZW5zYW8gY29tIGltcHV0YWNhbwoKIyBDYWxjdWxhciBwcm9wb3LDp8OjbyB0b3RhbApoeXBfZmluYWwgPC0gaHlwX2ZpbmFsICU+JQogIG11dGF0ZSh0b3RhbCA9IDEwMCAqIGNvbnRhZ2VtX2RlX3V0ZW50ZXNfaW5zY3JpdG9zX2NvbV9oaXBlcnRlbnNhb19hcnRlcmlhbF9jb21fcHJlc3Nhb19hcnRlcmlhbF9pbmZlcmlvcl9hXzE1MF85MF9tbWhnX24gLyBwcm9wb3JjYW9faGlwZXJ0ZW5zb3NfNjVfYV9jb21fcGFfMTUwXzkwKQoKIyBUb3RhbCBwb3IgYW5vICh0b2RvcyBvcyB1dGVudGVzKQpoaXBlcnRlbnNhb19hbm8gPC0gaHlwX2ZpbmFsICU+JQogIG11dGF0ZShBbm8gPSB5ZWFyKHltKHRlbXBvKSkpICU+JQogIGdyb3VwX2J5KEFubykgJT4lCiAgc3VtbWFyaXNlKHRvdGFsID0gc3VtKGFzLm51bWVyaWModG90YWwpLCBuYS5ybSA9IFRSVUUpLCAuZ3JvdXBzID0gImRyb3AiKSAlPiUKICBzdF9zZXRfZ2VvbWV0cnkoTlVMTCkKCmdncGxvdChoaXBlcnRlbnNhb19hbm8sIGFlcyh4ID0gZmFjdG9yKEFubyksIHkgPSB0b3RhbCkpICsKICBnZW9tX2NvbChmaWxsID0gInN0ZWVsYmx1ZSIpICsKICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcm91bmQodG90YWwpKSwgdmp1c3QgPSAtMC4yNSwgc2l6ZSA9IDMpICsKICBsYWJzKHRpdGxlID0gIlRvdGFsIGRlIFV0ZW50ZXMgY29tIEhpcGVydGVuc8OjbyBwb3IgQW5vIiwKICAgICAgIHggPSAiQW5vIiwKICAgICAgIHkgPSAiVG90YWwgZGUgVXRlbnRlcyIpICsKICB0aGVtZV9taW5pbWFsKCkKCiMgVG90YWwgcG9yIGFubyBwYXJhIHBlc3NvYXMgY29tIG1lbm9zIGRlIDY1IGFub3MKaGlwZXJ0ZW5zYW9fYW5vX21lbm9zXzY1IDwtIGh5cF9maW5hbCAlPiUKICBtdXRhdGUoQW5vID0geWVhcih5bSh0ZW1wbykpKSAlPiUKICBncm91cF9ieShBbm8pICU+JQogIHN1bW1hcmlzZShoaXBfbWVub3NfNjUgPSBzdW0oYXMubnVtZXJpYyhjb250YWdlbV9kZV91dGVudGVzX2luc2NyaXRvc19jb21faGlwZXJ0ZW5zYW9fYXJ0ZXJpYWxfY29tX3ByZXNzYW9fYXJ0ZXJpYWxfaW5mZXJpb3JfYV8xNTBfOTBfbW1oZ19uKSwgbmEucm0gPSBUUlVFKSwgLmdyb3VwcyA9ICJkcm9wIikgJT4lCiAgc3Rfc2V0X2dlb21ldHJ5KE5VTEwpCgpnZ3Bsb3QoaGlwZXJ0ZW5zYW9fYW5vX21lbm9zXzY1LCBhZXMoeCA9IGZhY3RvcihBbm8pLCB5ID0gaGlwX21lbm9zXzY1KSkgKwogIGdlb21fY29sKGZpbGwgPSAic3RlZWxibHVlIikgKwogIGdlb21fdGV4dChhZXMobGFiZWwgPSByb3VuZChoaXBfbWVub3NfNjUpKSwgdmp1c3QgPSAtMC4yNSwgc2l6ZSA9IDMpICsKICBsYWJzKHRpdGxlID0gIlRvdGFsIGRlIFV0ZW50ZXMgY29tIG1lbm9zIGRlIDY1IGFub3MgY29tIEhpcGVydGVuc8OjbyBwb3IgQW5vIiwKICAgICAgIHggPSAiQW5vIiwKICAgICAgIHkgPSAiVG90YWwgZGUgVXRlbnRlcyIpICsKICB0aGVtZV9taW5pbWFsKCkKCiMgQ29tcGFyYcOnw6NvIGVudHJlIG1lbm9zIGRlIDY1IGUgNjUgb3UgbWFpcwpoaXBlcnRlbnNhb19jb21wX2FubyA8LSBoaXBlcnRlbnNhb19hbm8gJT4lCiAgbGVmdF9qb2luKGhpcGVydGVuc2FvX2Fub19tZW5vc182NSwgYnkgPSAiQW5vIikgJT4lCiAgbXV0YXRlKAogICAgaGlwX21lbm9zXzY1ID0gaWZlbHNlKGlzLm5hKGhpcF9tZW5vc182NSksIDAsIGhpcF9tZW5vc182NSksCiAgICBoaXBfbWFpc182NSA9IHRvdGFsIC0gaGlwX21lbm9zXzY1CiAgKSAlPiUKICBzZWxlY3QoQW5vLCBoaXBfbWVub3NfNjUsIGhpcF9tYWlzXzY1KSAlPiUKICBwaXZvdF9sb25nZXIoCiAgICBjb2xzID0gYyhoaXBfbWVub3NfNjUsIGhpcF9tYWlzXzY1KSwKICAgIG5hbWVzX3RvID0gIkdyb3VwIiwKICAgIHZhbHVlc190byA9ICJ0b3RhbCIKICApICU+JQogIG11dGF0ZSgKICAgIEdyb3VwID0gZHBseXI6OnJlY29kZShHcm91cCwKICAgICAgICAgICAgICAgICAgICAgICAgICAiaGlwX21lbm9zXzY1IiA9ICJVbmRlciA2NSB5ZWFycyBvbGQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICJoaXBfbWFpc182NSIgPSAiNjUgeWVhcnMgb3Igb2xkZXIiKQogICkKCiMgR3LDoWZpY28gZW1waWxoYWRvCmdncGxvdChoaXBlcnRlbnNhb19jb21wX2FubywgYWVzKHggPSBmYWN0b3IoQW5vKSwgeSA9IHRvdGFsLCBmaWxsID0gR3JvdXApKSArCiAgZ2VvbV9jb2woKSArCiAgbGFicygKICAgIHRpdGxlID0gIiBDb250cm9sbGVkIEh5cGVydGVuc2lvbiBieSBBZ2UgYW5kIFllYXIiLAogICAgeCA9ICJZZWFyIiwKICAgIHkgPSAiTnVtYmVyIG9mIFBhdGllbnRzIgogICkgKwogIHRoZW1lX21pbmltYWwoKQoKCgojIEhpcGVydGVuc8OjbyBwb3IgbcOqcyAtIFRvdGFsCmhpcGVydGVuc2FvX21lcyA8LSBoeXBfZmluYWwgJT4lCiAgbXV0YXRlKERhdGEgPSB5bSh0ZW1wbyksCiAgICAgICAgIE1lcyA9IG1vbnRoKERhdGEsIGxhYmVsID0gVFJVRSwgYWJiciA9IEZBTFNFKSkgJT4lICAKICBncm91cF9ieShNZXMpICU+JQogIHN1bW1hcmlzZSh0b3RhbCA9IHN1bShhcy5udW1lcmljKHRvdGFsKSwgbmEucm0gPSBUUlVFKSwgLmdyb3VwcyA9ICJkcm9wIikgJT4lCiAgYXJyYW5nZShtYXRjaChNZXMsIG1vbnRoLm5hbWUpKSAlPiUKICBzdF9zZXRfZ2VvbWV0cnkoTlVMTCkKCmdncGxvdChoaXBlcnRlbnNhb19tZXMsIGFlcyh4ID0gTWVzLCB5ID0gdG90YWwpKSArCiAgZ2VvbV9jb2woZmlsbCA9ICJzdGVlbGJsdWUiKSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHJvdW5kKHRvdGFsKSksIHZqdXN0ID0gLTAuMjUsIHNpemUgPSAzKSArCiAgbGFicyh0aXRsZSA9ICJUb3RhbCBkZSBVdGVudGVzIGNvbSBIaXBlcnRlbnPDo28gcG9yIE3DqnMiLAogICAgICAgeCA9ICJNw6pzIiwKICAgICAgIHkgPSAiVG90YWwgZGUgVXRlbnRlcyIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0ID0gMC41LCBoanVzdCA9IDEpKQoKCiMgSGlwZXJ0ZW5zw6NvIHBvciBtw6pzIC0gTWVub3MgZGUgNjUKaGlwZXJ0ZW5zYW9fbWVzXzY1IDwtIGh5cF9maW5hbCAlPiUKICBtdXRhdGUoRGF0YV82NSA9IHltKHRlbXBvKSwKICAgICAgICAgTWVzXzY1ID0gbW9udGgoRGF0YV82NSwgbGFiZWwgPSBUUlVFLCBhYmJyID0gRkFMU0UpKSAlPiUgIAogIGdyb3VwX2J5KE1lc182NSkgJT4lCiAgc3VtbWFyaXNlKGhpcF9tZW5vc182NSA9IHN1bShhcy5udW1lcmljKGNvbnRhZ2VtX2RlX3V0ZW50ZXNfaW5zY3JpdG9zX2NvbV9oaXBlcnRlbnNhb19hcnRlcmlhbF9jb21fcHJlc3Nhb19hcnRlcmlhbF9pbmZlcmlvcl9hXzE1MF85MF9tbWhnX24pLCBuYS5ybSA9IFRSVUUpLCAuZ3JvdXBzID0gImRyb3AiKSAlPiUKICBhcnJhbmdlKG1hdGNoKE1lc182NSwgbW9udGgubmFtZSkpICU+JQogIHN0X3NldF9nZW9tZXRyeShOVUxMKQoKZ2dwbG90KGhpcGVydGVuc2FvX21lc182NSwgYWVzKHggPSBNZXNfNjUsIHkgPSBoaXBfbWVub3NfNjUpKSArCiAgZ2VvbV9jb2woZmlsbCA9ICJzdGVlbGJsdWUiKSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHJvdW5kKGhpcF9tZW5vc182NSkpLCB2anVzdCA9IC0wLjI1LCBzaXplID0gMykgKwogIGxhYnModGl0bGUgPSAiVXRlbnRlcyA8NjUgYW5vcyBjb20gSGlwZXJ0ZW5zw6NvIHBvciBNw6pzIiwKICAgICAgIHggPSAiTcOqcyIsCiAgICAgICB5ID0gIlRvdGFsIGRlIFV0ZW50ZXMiKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNSwgaGp1c3QgPSAxKSkKCgojIFRhYmVsYSBkZSBtZXNlcyBlbSBwb3J0dWd1w6pzCm1lc2VzX3B0IDwtIGMoImphbmVpcm8iLCAiZmV2ZXJlaXJvIiwgIm1hcsOnbyIsICJhYnJpbCIsICJtYWlvIiwgImp1bmhvIiwgCiAgICAgICAgICAgICAgImp1bGhvIiwgImFnb3N0byIsICJzZXRlbWJybyIsICJvdXR1YnJvIiwgIm5vdmVtYnJvIiwgImRlemVtYnJvIikKCgptZXNfbG9va3VwIDwtIGMoCiAgImphbnVhcnkiID0gImphbmVpcm8iLCAiZmVicnVhcnkiID0gImZldmVyZWlybyIsICJtYXJjaCIgPSAibWFyw6dvIiwKICAiYXByaWwiID0gImFicmlsIiwgIm1heSIgPSAibWFpbyIsICJqdW5lIiA9ICJqdW5obyIsCiAgImp1bHkiID0gImp1bGhvIiwgImF1Z3VzdCIgPSAiYWdvc3RvIiwgInNlcHRlbWJlciIgPSAic2V0ZW1icm8iLAogICJvY3RvYmVyIiA9ICJvdXR1YnJvIiwgIm5vdmVtYmVyIiA9ICJub3ZlbWJybyIsICJkZWNlbWJlciIgPSAiZGV6ZW1icm8iCikKCgojIEp1bnRhciB0b3RhbCBlIDw2NSwgY2FsY3VsYXIgPj02NQpoaXBlcnRlbnNhb19jb21wX21lcyA8LSBoaXBlcnRlbnNhb19tZXMgJT4lCiAgbGVmdF9qb2luKGhpcGVydGVuc2FvX21lc182NSwgYnkgPSBjKCJNZXMiID0gIk1lc182NSIpKSAlPiUKICBtdXRhdGUoCiAgICBoaXBfbWVub3NfNjUgPSBpZmVsc2UoaXMubmEoaGlwX21lbm9zXzY1KSwgMCwgaGlwX21lbm9zXzY1KSwKICAgIGhpcF9tYWlzXzY1ID0gdG90YWwgLSBoaXBfbWVub3NfNjUsCiAgICBNZXMgPSBkcGx5cjo6cmVjb2RlKHRvbG93ZXIoYXMuY2hhcmFjdGVyKE1lcykpLCAhISFtZXNfbG9va3VwKSwKICAgIE1lcyA9IGZhY3RvcihNZXMsIGxldmVscyA9IG1lc2VzX3B0KQogICkgJT4lCiAgc2VsZWN0KE1lcywgaGlwX21lbm9zXzY1LCBoaXBfbWFpc182NSkgJT4lCiAgcGl2b3RfbG9uZ2VyKAogICAgY29scyA9IGMoaGlwX21lbm9zXzY1LCBoaXBfbWFpc182NSksCiAgICBuYW1lc190byA9ICJHcm91cCIsCiAgICB2YWx1ZXNfdG8gPSAiVG90YWxfaGlwIgogICkgJT4lCiAgbXV0YXRlKAogICAgR3JvdXAgPSBkcGx5cjo6cmVjb2RlKEdyb3VwLAogICAgICAgICAgICAgICAgICAgICAgICAgICJoaXBfbWVub3NfNjUiID0gIlVuZGVyIDY1IHllYXJzIG9sZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgImhpcF9tYWlzXzY1IiA9ICI2NSB5ZWFycyBvciBvbGRlciIpCiAgKQoKIyBHcsOhZmljbyBmaW5hbCAtIGJhcnJhcyBlZ3JvdXBfYnkoKSMgR3LDoWZpY28gZmluYWwgLSBiYXJyYXMgZW1waWxoYWRhcwpnZ3Bsb3QoaGlwZXJ0ZW5zYW9fY29tcF9tZXMsIGFlcyh4ID0gTWVzLCB5ID0gVG90YWxfaGlwLCBmaWxsID0gR3JvdXApKSArCiAgZ2VvbV9jb2woKSArCiAgbGFicygKICAgIHRpdGxlID0gIiBDb250cm9sbGVkIEh5cGVydGVuc2lvbiBieSBBZ2UgYW5kIE1vbnRoIiwKICAgIHggPSAiTW9udGgiLAogICAgeSA9ICJOdW1iZXIgb2YgcGF0aWVudHMiCiAgKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNSwgaGp1c3QgPSAxKSkKYGBgCgpgYGB7cn0KCiMjIEFuw6FsaXNlIGRvIGRhdGFzZXQgYXZjOiAKCiNRdWFpcyBvcyBhbm9zIGUgbWVzZXMgw6kgcXVlIGVzdMOjbyByZWdpc3RhZG9zIG5vIEFWQwptZXNlc19wb3JfYW5vX2F2YyA8LSBhdmMgJT4lCiAgbXV0YXRlKEFub19hdmMgPSB5ZWFyKHltKFBlcsOtb2RvKSksCiAgICAgICAgIE1lc19hdmMgPSBtb250aCh5bShQZXLDrW9kbyksIGxhYmVsID0gVFJVRSwgYWJiciA9IEZBTFNFKSkgJT4lCiAgZGlzdGluY3QoQW5vX2F2YywgTWVzX2F2YykgJT4lCiAgYXJyYW5nZShBbm9fYXZjLCBNZXNfYXZjKSAlPiUKICBncm91cF9ieShBbm9fYXZjKSAlPiUKICBzdW1tYXJpc2UoTWVzZXNfRGlzcG9uaXZlaXMgPSBwYXN0ZShNZXNfYXZjLCBjb2xsYXBzZSA9ICIsICIpKQoKI1ZlciBtaXNzaW5nIHZhbHVlcyAKc2FwcGx5KGF2YywgZnVuY3Rpb24oeCkgc3VtKGlzLm5hKHgpIHwgeCA9PSAiIikpCgojIERpc3RyaWJ1acOnw6NvIHBvciBHw6luZXJvIGNvbSBBVkMgCgphdmNfZ2VuZXJvIDwtIGF2YyAlPiUKICBncm91cF9ieShHw6luZXJvLmRhLlbDrXRpbWEpICU+JQogIHN1bW1hcmlzZShUb3RhbF9BVkMgPSBzdW0oYXMubnVtZXJpYyhgTi7Cui5kZS5yZWdpc3Rvcy5WaWEuVmVyZGUuQVZDYCksIG5hLnJtID0gVFJVRSkpICU+JQogIGFycmFuZ2UoZGVzYyhUb3RhbF9BVkMpKQoKZ2dwbG90KGF2Y19nZW5lcm8sIGFlcyh4ID0gcmVvcmRlcihHw6luZXJvLmRhLlbDrXRpbWEsIC1Ub3RhbF9BVkMpLCB5ID0gVG90YWxfQVZDLCBmaWxsID0gR8OpbmVyby5kYS5Ww610aW1hKSkgKwogIGdlb21fY29sKCkgKwogIGdlb21fdGV4dChhZXMobGFiZWwgPSBUb3RhbF9BVkMpLCB2anVzdCA9IC0wLjIsIHNpemUgPSAyKSArCiAgbGFicyh0aXRsZSA9ICJUb3RhbCBkZSBSZWdpc3RvcyBkZSBBVkMgcG9yIEfDqW5lcm8iLAogICAgICAgeCA9ICJHw6luZXJvIiwKICAgICAgIHkgPSAiVG90YWwgZGUgQVZDIikgKwogIHRoZW1lX21pbmltYWwoKQoKIyBEaXN0cmlidWnDp8OjbyBwb3IgR8OpbmVybyBjb20gQVZDIGVtIGNhZGEgYW5vCgphdmNfZ2VuZXJvX2FubyA8LSBhdmMgJT4lCiAgbXV0YXRlKEFubyA9IHllYXIoeW0oUGVyw61vZG8pKSkgJT4lCiAgZ3JvdXBfYnkoQW5vLCBHw6luZXJvLmRhLlbDrXRpbWEpICU+JQogIHN1bW1hcmlzZShUb3RhbF9BVkMgPSBzdW0oYXMubnVtZXJpYyhOLsK6LmRlLnJlZ2lzdG9zLlZpYS5WZXJkZS5BVkMpLCBuYS5ybSA9IFRSVUUpLCAuZ3JvdXBzID0gImRyb3AiKQoKIyBUcmFkdXppciB2YWxvcmVzIGRlICdHw6luZXJvLmRhLlbDrXRpbWEnCmF2YyRHw6luZXJvLmRhLlbDrXRpbWEgPC0gaWZlbHNlKGF2YyRHw6luZXJvLmRhLlbDrXRpbWEgPT0gIkZlbWluaW5vIiwgIkZlbWFsZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UoYXZjJEfDqW5lcm8uZGEuVsOtdGltYSA9PSAiTWFzY3VsaW5vIiwgIk1hbGUiLCBhdmMkR8OpbmVyby5kYS5Ww610aW1hKSkKCmdncGxvdChhdmNfZ2VuZXJvX2FubywgYWVzKHggPSBmYWN0b3IoQW5vKSwgeSA9IFRvdGFsX0FWQywgZmlsbCA9IEfDqW5lcm8uZGEuVsOtdGltYSkpICsKICBnZW9tX2NvbChwb3NpdGlvbiA9ICJkb2RnZSIpICsKICBnZW9tX3RleHQoYWVzKGxhYmVsID0gVG90YWxfQVZDKSwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuOSksIHZqdXN0ID0gLTAuMjUsIHNpemUgPSAzKSArCiAgbGFicyh0aXRsZSA9ICJUb3RhbCBTdHJva2UgUmVjb3JkcyBieSBZZWFyIGFuZCBHZW5kZXIiLAogICAgICAgeCA9ICJZZWFyIiwKICAgICAgIHkgPSAiVG90YWwgU3Ryb2tlIFJlY29yZHMiLAogICAgICAgZmlsbCA9ICJHZW5kZXIiKSArCiAgdGhlbWVfbWluaW1hbCgpCgoKIyBEaXN0cmlidWnDp8OjbyBwb3IgR8OpbmVybyBjb20gQVZDIGVtIGNhZGEgbcOqcwphdmNfZ2VuZXJvX21lcyA8LSBhdmMgJT4lCiAgbXV0YXRlKE1lc19Bbm8gPSBmb3JtYXQoeW0oUGVyw61vZG8pLCAiJVktJW0iKSkgJT4lCiAgZ3JvdXBfYnkoTWVzX0FubywgYEfDqW5lcm8uZGEuVsOtdGltYWApICU+JQogIHN1bW1hcmlzZShUb3RhbF9BVkMgPSBzdW0oYXMubnVtZXJpYyhgTi7Cui5kZS5yZWdpc3Rvcy5WaWEuVmVyZGUuQVZDYCksIG5hLnJtID0gVFJVRSksIC5ncm91cHMgPSAiZHJvcCIpCgpnZ3Bsb3QoYXZjX2dlbmVyb19tZXMsIGFlcyh4ID0gTWVzX0FubywgeSA9IFRvdGFsX0FWQywgZmlsbCA9IGBHw6luZXJvLmRhLlbDrXRpbWFgKSkgKwogIGdlb21fY29sKHBvc2l0aW9uID0gImRvZGdlIikgKwogIGxhYnModGl0bGUgPSAiU3Ryb2tlIERpc3RyaWJ1dGlvbiBieSBNb250aCBhbmQgR2VuZGVyIiwKICAgICAgIHggPSAiTW9udGgiLCB5ID0gIlRvdGFsIFN0cm9rZSBSZWNvcmRzIiwgZmlsbCA9ICJHZW5kZXIiKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKQoKIyBEaXN0cmlidWnDp8OjbyBGYWl4YSBFdMOhcmlhIGNvbSBBVkMgbm8gdG90YWwgZG9zIGFub3MKCiMgRGVmaW5lIHRoZSBjb3JyZWN0IG9yZGVyIG9mIGFnZSByYW5nZXMKZmFpeGFfb3JkZW0gPC0gYygiMCAtIDE3IiwgIjE4IC0gMjkiLCAiMzAgLSAzOSIsICI0MCAtIDQ5IiwgIjUwIC0gNTkiLCAKICAgICAgICAgICAgICAgICAiNjAgLSA2OSIsICI3MCAtIDc5IiwgIjgwIC0gODkiLCAiOTAgLSA5OSIsICI+MTAwIikKCiMgQXBwbHkgdGhlIG9yZGVyIHVzaW5nIGZhY3RvcgphdmNfaWRhZGUgPC0gYXZjICU+JQogIGdyb3VwX2J5KGBGYWl4YS5FdMOhcmlhLmRhLlbDrXRpbWFgKSAlPiUKICBzdW1tYXJpc2UoVG90YWxfQVZDID0gc3VtKGFzLm51bWVyaWMoYE4uwrouZGUucmVnaXN0b3MuVmlhLlZlcmRlLkFWQ2ApLCBuYS5ybSA9IFRSVUUpKSAlPiUKICBtdXRhdGUoYEZhaXhhLkV0w6FyaWEuZGEuVsOtdGltYWAgPSBmYWN0b3IoYEZhaXhhLkV0w6FyaWEuZGEuVsOtdGltYWAsIGxldmVscyA9IGZhaXhhX29yZGVtKSkgJT4lCiAgYXJyYW5nZShgRmFpeGEuRXTDoXJpYS5kYS5Ww610aW1hYCkKCiMgUGxvdApnZ3Bsb3QoYXZjX2lkYWRlLCBhZXMoeCA9IGBGYWl4YS5FdMOhcmlhLmRhLlbDrXRpbWFgLCB5ID0gVG90YWxfQVZDKSkgKwogIGdlb21fY29sKGZpbGwgPSAic3RlZWxibHVlIikgKwogIGdlb21fdGV4dChhZXMobGFiZWwgPSBUb3RhbF9BVkMpLCB2anVzdCA9IC0wLjIsIHNpemUgPSAyKSArCiAgbGFicyh0aXRsZSA9ICJUb3RhbCBkZSBSZWdpc3RvcyBkZSBBVkMgcG9yIEZhaXhhIEV0w6FyaWEiLAogICAgICAgeCA9ICJGYWl4YSBFdMOhcmlhIiwKICAgICAgIHkgPSAiVG90YWwgZGUgQVZDIikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkKCiMgRGlzdHJpYnVpw6fDo28gRmFpeGEgRXTDoXJpYSBjb20gQVZDIGVtIGNhZGEgYW5vCgphdmNfZmFpeGFfYW5vIDwtIGF2YyAlPiUKICBtdXRhdGUoQW5vID0geWVhcih5bShQZXLDrW9kbykpKSAlPiUKICBncm91cF9ieShBbm8sIGBGYWl4YS5FdMOhcmlhLmRhLlbDrXRpbWFgKSAlPiUKICBzdW1tYXJpc2UoVG90YWxfQVZDID0gc3VtKGFzLm51bWVyaWMoYE4uwrouZGUucmVnaXN0b3MuVmlhLlZlcmRlLkFWQ2ApLCBuYS5ybSA9IFRSVUUpLCAuZ3JvdXBzID0gImRyb3AiKSAlPiUgbXV0YXRlKGBGYWl4YS5FdMOhcmlhLmRhLlbDrXRpbWFgID0gZmFjdG9yKGBGYWl4YS5FdMOhcmlhLmRhLlbDrXRpbWFgLCBsZXZlbHMgPSBmYWl4YV9vcmRlbSkpICU+JQogIGFycmFuZ2UoYEZhaXhhLkV0w6FyaWEuZGEuVsOtdGltYWApCgoKZ2dwbG90KGF2Y19mYWl4YV9hbm8sIGFlcyh4ID0gZmFjdG9yKEFubyksIHkgPSBUb3RhbF9BVkMsIGZpbGwgPSBgRmFpeGEuRXTDoXJpYS5kYS5Ww610aW1hYCkpICsKICBnZW9tX2NvbChwb3NpdGlvbiA9ICJkb2RnZSIpICsKICBsYWJzKHRpdGxlID0gIlRvdGFsIFN0cm9rZSBSZWNvcmRzIGJ5IFllYXIgYW5kIEFnZSBHcm91cCIsCiAgICAgICB4ID0gIlllYXIiLAogICAgICAgeSA9ICJUb3RhbCBTdHJva2UgUmVjb3JkcyIsCiAgICAgICBmaWxsID0gIkFnZSBHcm91cCIpICsKICB0aGVtZV9taW5pbWFsKCkKCiMgRGlzdHJpYnVpw6fDo28gRmFpeGEgRXTDoXJpYSBjb20gQVZDIGVtIGNhZGEgbcOqcwoKYXZjX2ZhaXhhX21lcyA8LSBhdmMgJT4lCiAgbXV0YXRlKE1lc19Bbm8gPSBmb3JtYXQoeW0oUGVyw61vZG8pLCAiJVktJW0iKSkgJT4lCiAgZ3JvdXBfYnkoTWVzX0FubywgYEZhaXhhLkV0w6FyaWEuZGEuVsOtdGltYWApICU+JQogIHN1bW1hcmlzZShUb3RhbF9BVkMgPSBzdW0oYXMubnVtZXJpYyhgTi7Cui5kZS5yZWdpc3Rvcy5WaWEuVmVyZGUuQVZDYCksIG5hLnJtID0gVFJVRSksIC5ncm91cHMgPSAiZHJvcCIpICU+JSBtdXRhdGUoYEZhaXhhLkV0w6FyaWEuZGEuVsOtdGltYWAgPSBmYWN0b3IoYEZhaXhhLkV0w6FyaWEuZGEuVsOtdGltYWAsIGxldmVscyA9IGZhaXhhX29yZGVtKSkgJT4lCiAgYXJyYW5nZShgRmFpeGEuRXTDoXJpYS5kYS5Ww610aW1hYCkKCmdncGxvdChhdmNfZmFpeGFfbWVzLCBhZXMoeCA9IE1lc19Bbm8sIHkgPSBUb3RhbF9BVkMsIGZpbGwgPSBgRmFpeGEuRXTDoXJpYS5kYS5Ww610aW1hYCkpICsKICBnZW9tX2NvbChwb3NpdGlvbiA9ICJkb2RnZSIpICsKICBsYWJzKHRpdGxlID0gIlN0cm9rZSBEaXN0cmlidXRpb24gYnkgTW9udGggYW5kIEFnZSBHcm91cCIsCiAgICAgICB4ID0gIk1vbnRoIiwgeSA9ICJUb3RhbCBTdHJva2UgUmVjb3JkcyIsIGZpbGwgPSAiQWdlIEdyb3VwZSIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpCgojIEfDqW5lcm8gw5cgRmFpeGEgRXTDoXJpYSBhbyBsb25nb3MgZG8gcGVyw61vZG8gCgphdmNfY3Jvc3MgPC0gYXZjICU+JQogIGdyb3VwX2J5KGBHw6luZXJvLmRhLlbDrXRpbWFgLCBgRmFpeGEuRXTDoXJpYS5kYS5Ww610aW1hYCkgJT4lCiAgc3VtbWFyaXNlKFRvdGFsX0FWQyA9IHN1bShhcy5udW1lcmljKGBOLsK6LmRlLnJlZ2lzdG9zLlZpYS5WZXJkZS5BVkNgKSwgbmEucm0gPSBUUlVFKSkgJT4lCiAgdW5ncm91cCgpICU+JSBtdXRhdGUoYEZhaXhhLkV0w6FyaWEuZGEuVsOtdGltYWAgPSBmYWN0b3IoYEZhaXhhLkV0w6FyaWEuZGEuVsOtdGltYWAsIGxldmVscyA9IGZhaXhhX29yZGVtKSkgJT4lCiAgYXJyYW5nZShgRmFpeGEuRXTDoXJpYS5kYS5Ww610aW1hYCkKCmdncGxvdChhdmNfY3Jvc3MsIGFlcyh4ID0gYEZhaXhhLkV0w6FyaWEuZGEuVsOtdGltYWAsIHkgPSBUb3RhbF9BVkMsIGZpbGwgPSBgR8OpbmVyby5kYS5Ww610aW1hYCkpICsKICBnZW9tX2NvbChwb3NpdGlvbiA9ICJkb2RnZSIpICsKICBsYWJzKHRpdGxlID0gIkRpc3RyaWJ1acOnw6NvIGRlIEFWQyBwb3IgR8OpbmVybyBlIEZhaXhhIEV0w6FyaWEiLCB4ID0gIkZhaXhhIEV0w6FyaWEiLCB5ID0gIlRvdGFsIGRlIEFWQyIsIGZpbGwgPSAiR8OpbmVybyIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpCmBgYAoKYGBge3J9CiMgQ29ycmVsYcOnw6NvIGVudHJlIEhpcGVydGVuc29zIGUgQVZDIHBvciBncnVwbyBldMOhcmlvIChtYWlvcmVzIGRlIDY1IGFub3MgZSBtZW5vcmVzIGRlIDY1IGFub3MpCgojIENsZWFuIG5hbWVzCmF2YyA8LSBhdmMgJT4lIGphbml0b3I6OmNsZWFuX25hbWVzKCkKCiMgRml4IGNvbHVtbiBuYW1lCm5hbWVzKGF2YylbbmFtZXMoYXZjKSA9PSAibl9vX2RlX3JlZ2lzdG9zX3ZpYV92ZXJkZV9hdmMiXSA8LSAibl9kZV9yZWdpc3Rvc192aWFfdmVyZGVfYXZjIgoKIyBEaXZpZGltb3MgbyBBVkMgZW0gbWFpb3JlcyBkZSA2NSBhbm9zIGUgbWVub3JlcyBkZSA2NSBhbm9zCmF2Y19jbGVhbiA8LSBhdmMgJT4lCiAgbXV0YXRlKAogICAgZmFpeGFfaW5pY2lvID0gYXMubnVtZXJpYyhzdHJfZXh0cmFjdChmYWl4YV9ldGFyaWFfZGFfdml0aW1hLCAiXlxcZCsiKSksCiAgICBmYWl4YV9maW0gPSBhcy5udW1lcmljKHN0cl9leHRyYWN0KGZhaXhhX2V0YXJpYV9kYV92aXRpbWEsICJcXGQrJCIpKSwKICAgIEdyb3VwID0gY2FzZV93aGVuKAogICAgICBmYWl4YV9pbmljaW8gPCA2OSB+ICJVbmRlciA2NSB5ZWFycyBvbGQiLAogICAgICBUUlVFIH4gIjY1IHllYXJzIG9yIG9sZGVyIgogICAgKSwKICAgIG1lc19udW0gPSBhcy5pbnRlZ2VyKHN0cl9zdWIocGVyaW9kbywgNiwgNykpLAogICAgbWVzID0gZmFjdG9yKG1lc2VzX3B0W21lc19udW1dLCBsZXZlbHMgPSBtZXNlc19wdCksCiAgICBuX2RlX3JlZ2lzdG9zX3ZpYV92ZXJkZV9hdmMgPSBhcy5udW1lcmljKG5fZGVfcmVnaXN0b3NfdmlhX3ZlcmRlX2F2YykKICApICU+JQogIGdyb3VwX2J5KG1lcywgR3JvdXApICU+JQogIHN1bW1hcmlzZSh0b3RhbF9hdmMgPSBzdW0obl9kZV9yZWdpc3Rvc192aWFfdmVyZGVfYXZjLCBuYS5ybSA9IFRSVUUpLCAuZ3JvdXBzID0gImRyb3AiKQoKIyBGaWx0cmFyIGRhZG9zIGRlIGhpcGVydGVuc8OjbyBkZSAyMDIyLTAxIGEgMjAyNC0wMgpoeXBfZmlsdHJhZG8gPC0gaHlwX2ZpbmFsICU+JQogIHN0X3NldF9nZW9tZXRyeShOVUxMKSAlPiUKICBtdXRhdGUoRGF0YSA9IHltKHRlbXBvKSkgJT4lCiAgZmlsdGVyKERhdGEgPj0geW0oIjIwMjItMDEiKSAmIERhdGEgPD0geW0oIjIwMjQtMDIiKSkKCiMgSGlwZXJ0ZW5zw6NvIHRvdGFsIHBvciBtw6pzCmhpcGVydGVuc2FvX21lc19maWx0cmFkbyA8LSBoeXBfZmlsdHJhZG8gJT4lCiAgbXV0YXRlKE1lcyA9IG1vbnRoKERhdGEsIGxhYmVsID0gVFJVRSwgYWJiciA9IEZBTFNFKSkgJT4lCiAgZ3JvdXBfYnkoTWVzKSAlPiUKICBzdW1tYXJpc2UodG90YWwgPSBzdW0oYXMubnVtZXJpYyh0b3RhbCksIG5hLnJtID0gVFJVRSksIC5ncm91cHMgPSAiZHJvcCIpICU+JQogIGFycmFuZ2UobWF0Y2goTWVzLCBtb250aC5uYW1lKSkKCiMgSGlwZXJ0ZW5zw6NvIGVtIG1lbm9yZXMgZGUgNjUgYW5vcwpoaXBlcnRlbnNhb19tZXNfNjVfZmlsdHJhZG8gPC0gaHlwX2ZpbHRyYWRvICU+JQogIG11dGF0ZShNZXMgPSBtb250aChEYXRhLCBsYWJlbCA9IFRSVUUsIGFiYnIgPSBGQUxTRSkpICU+JQogIGdyb3VwX2J5KE1lcykgJT4lCiAgc3VtbWFyaXNlKGhpcF82NSA9IHN1bShhcy5udW1lcmljKGNvbnRhZ2VtX2RlX3V0ZW50ZXNfaW5zY3JpdG9zX2NvbV9oaXBlcnRlbnNhb19hcnRlcmlhbF9jb21fcHJlc3Nhb19hcnRlcmlhbF9pbmZlcmlvcl9hXzE1MF85MF9tbWhnX24pLCBuYS5ybSA9IFRSVUUpLCAuZ3JvdXBzID0gImRyb3AiKSAlPiUKICBhcnJhbmdlKG1hdGNoKE1lcywgbW9udGgubmFtZSkpCgojIENvbWJpbmFyIGRhZG9zIGRlIGhpcGVydGVuc8OjbyBlIHByZXBhcmFyIGZvcm1hdG8gbG9uZ28KaGlwZXJ0ZW5zYW9fY29tcF9tZXNfZmlsdHJhZG8gPC0gaGlwZXJ0ZW5zYW9fbWVzX2ZpbHRyYWRvICU+JQogIGxlZnRfam9pbihoaXBlcnRlbnNhb19tZXNfNjVfZmlsdHJhZG8sIGJ5ID0gIk1lcyIpICU+JQogIG11dGF0ZSgKICAgIGhpcF82NSA9IGlmZWxzZShpcy5uYShoaXBfNjUpLCAwLCBoaXBfNjUpLAogICAgaGlwX21haXNfNjUgPSB0b3RhbCAtIGhpcF82NSwKICAgIE1lcyA9IG1lc19sb29rdXBbTWVzXSwKICAgIE1lcyA9IGZhY3RvcihNZXMsIGxldmVscyA9IG1lc2VzX3B0KQogICkgJT4lCiAgc2VsZWN0KE1lcywgaGlwXzY1LCBoaXBfbWFpc182NSkgJT4lCiAgcGl2b3RfbG9uZ2VyKAogICAgY29scyA9IGMoImhpcF82NSIsICJoaXBfbWFpc182NSIpLAogICAgbmFtZXNfdG8gPSAiR3JvdXAiLAogICAgdmFsdWVzX3RvID0gIlRvdGFsX2hpcCIKICApICU+JQogIG11dGF0ZSgKICAgIEdyb3VwID0gZHBseXI6OnJlY29kZShHcm91cCwKICAgICAgImhpcF82NSIgPSAiVW5kZXIgNjUgeWVhcnMgb2xkIiwKICAgICAgImhpcF9tYWlzXzY1IiA9ICI2NSB5ZWFycyBvciBvbGRlciIpCiAgKQoKIyBHcsOhZmljbyBlbXBpbGhhZG8gZGUgaGlwZXJ0ZW5zw6NvCmdncGxvdChoaXBlcnRlbnNhb19jb21wX21lc19maWx0cmFkbywgYWVzKHggPSBNZXMsIHkgPSBUb3RhbF9oaXAsIGZpbGwgPSBHcm91cCkpICsKICBnZW9tX2NvbCgpICsKICBsYWJzKAogICAgdGl0bGUgPSAiSGlwZXJ0ZW5zw6NvIHBvciBJZGFkZSBlIE3DqnMgKDIwMjItMDEgYSAyMDI0LTAyKSIsCiAgICB4ID0gIk3DqnMiLAogICAgeSA9ICJOw7ptZXJvIGRlIFV0ZW50ZXMiCiAgKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNSwgaGp1c3QgPSAxKSkKCiMgUmVzdW1vIHBhcmEgYW7DoWxpc2UKaGlwZXJ0ZW5zYW9fc3VtbWFyeSA8LSBoaXBlcnRlbnNhb19jb21wX21lc19maWx0cmFkbyAlPiUKICBncm91cF9ieShNZXMsIEdyb3VwKSAlPiUKICBzdW1tYXJpc2UoVG90YWxfSElQID0gc3VtKFRvdGFsX2hpcCksIC5ncm91cHMgPSAiZHJvcCIpICU+JQogIHJlbmFtZShtZXMgPSBNZXMpCgojIE1lcmdlIGNvbSBkYWRvcyBkZSBBVkMKbWVyZ2VkIDwtIGxlZnRfam9pbihoaXBlcnRlbnNhb19zdW1tYXJ5LCBhdmNfY2xlYW4sIGJ5ID0gYygibWVzIiwgIkdyb3VwIikpCgojIEJveHBsb3RzIHBhcmEgdmlzdWFsaXphw6fDo28gZGUgb3V0bGllcnMKZ2dwbG90KG1lcmdlZCwgYWVzKHggPSBHcm91cCwgeSA9IFRvdGFsX0hJUCkpICsKICBnZW9tX2JveHBsb3QoKSArCiAgbGFicyh0aXRsZSA9ICJCb3hwbG90IG9mIENvbnRyb2xsZWQgSHlwZXJ0ZW5zaW9uIGJ5IEFnZSBHcm91cCIsIHg9Ikdyb3VwIiwgeT0iVG90YWwgSHlwZXJ0ZW5zaW9uIFBhdGllbnRzIikKCmdncGxvdChtZXJnZWQsIGFlcyh4ID0gR3JvdXAsIHkgPSB0b3RhbF9hdmMpKSArCiAgZ2VvbV9ib3hwbG90KCkgKwogIGxhYnModGl0bGUgPSAiQm94cGxvdCBvZiBTdHJva2UgQ2FzZXMgYnkgQWdlIEdyb3VwIiwgeD0iR3JvdXAiLCB5PSJUb3RhbCBTdHJva2UgQ2FzZXMiKQoKI2NvbW8gaMOhIG91dGxpZXJzLCBmYXplbW9zIGNvbSBvIHNwZWFybWFuCgojIENvcnJlbGHDp8OjbyBkZSBTcGVhcm1hbgpjb3JfcmVzdWx0c19zcGVhcm1hbiA8LSBtZXJnZWQgJT4lCiAgZ3JvdXBfYnkoR3JvdXApICU+JQogIHN1bW1hcmlzZShjb3JyZWwgPSBjb3IoVG90YWxfSElQLCB0b3RhbF9hdmMsIG1ldGhvZCA9ICJzcGVhcm1hbiIpKQoKcHJpbnQoY29yX3Jlc3VsdHNfc3BlYXJtYW4pCgojIFNjYXR0ZXJwbG90IGNvbSByZWdyZXNzw6NvIHBhcmEgdmlzdWFsaXphw6fDo28KZ2dwbG90KG1lcmdlZCwgYWVzKHggPSBUb3RhbF9ISVAsIHkgPSB0b3RhbF9hdmMsIGNvbG9yID0gR3JvdXApKSArCiAgZ2VvbV9wb2ludChzaXplID0gMykgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gRkFMU0UpICsKICBmYWNldF93cmFwKH4gR3JvdXApICsKICBsYWJzKAogICAgdGl0bGUgPSAiQ29ycmVsYXRpb24gYmV0d2VlbiBDb250cm9sbGVkIEh5cGVydGVuc2lvbiBhbmQgU3Ryb2tlIGJ5IEFnZSBHcm91cCIsCiAgICB4ID0gIlRvdGFsIEh5cGVydGVuc2lvbiBQYXRpZW50cyIsCiAgICB5ID0gIlRvdGFsIFN0cm9rZSBDYXNlcyIKICApICsKICB0aGVtZV9taW5pbWFsKCkKCiMgUmVncmVzc8O1ZXMgbGluZWFyZXMgcG9yIGdydXBvCm1vZGVscyA8LSBtZXJnZWQgJT4lCiAgZ3JvdXBfYnkoR3JvdXApICU+JQogIGdyb3VwX21hcCh+IGxtKHRvdGFsX2F2YyB+IFRvdGFsX0hJUCwgZGF0YSA9IC54KSwgLmtlZXAgPSBUUlVFKQoKIyBSZXN1bW8gZGFzIHJlZ3Jlc3PDtWVzCnN1bW1hcnkobW9kZWxzW1sxXV0pICAjIFVuZGVyIDY1IHllYXJzIG9sZApzdW1tYXJ5KG1vZGVsc1tbMl1dKSAgIyA2NSB5ZWFycyBvciBvbGRlcgoKYGBgCgoKYGBge3J9CgojIFRvdGFsIGRlIFJlZ2lzdG9zIGRlIEFWQyBwb3IgRGlzdHJpdG8KYXZjX3JlZ2lhbyA8LSBhdmMgJT4lCiAgZ3JvdXBfYnkoYGRpc3RyaXRvX2RhX29jb3JyZW5jaWFgKSAlPiUKICBzdW1tYXJpc2UoVG90YWxfQVZDID0gc3VtKGFzLm51bWVyaWMoYG5fZGVfcmVnaXN0b3NfdmlhX3ZlcmRlX2F2Y2ApLCBuYS5ybSA9IFRSVUUpKSAlPiUKICBhcnJhbmdlKGRlc2MoVG90YWxfQVZDKSkgCgpnZ3Bsb3QoYXZjX3JlZ2lhbywgYWVzKHggPSByZW9yZGVyKGBkaXN0cml0b19kYV9vY29ycmVuY2lhYCwgLVRvdGFsX0FWQyksIHkgPSBUb3RhbF9BVkMpKSArCiAgZ2VvbV9jb2woZmlsbCA9ICJzdGVlbGJsdWUiKSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IFRvdGFsX0FWQyksIHZqdXN0ID0gLTAuMiwgc2l6ZSA9IDIpICsKICBsYWJzKHRpdGxlID0gIlRvdGFsIFN0cm9rZSBSZWNvcmRzIGJ5IERpc3RyaWN0IiwKICAgICAgIHggPSAiRGlzdHJpY3QiLCB5ID0gIlBhdGllbnRzIikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkKCiMgRGlzdHJpYnVpw6fDo28gYW8gbG9uZ28gZG8gdGVtcG8gcG9yIGRpc3RyaXRvCgphdmNfcmVnaWFvX3RlbXBvIDwtIGF2YyAlPiUKICBtdXRhdGUoTWVzX0FubyA9IGZvcm1hdCh5bShwZXJpb2RvKSwgIiVZLSVtIikpICU+JQogIGdyb3VwX2J5KE1lc19Bbm8sIGBkaXN0cml0b19kYV9vY29ycmVuY2lhYCkgJT4lCiAgc3VtbWFyaXNlKFRvdGFsX0FWQyA9IHN1bShhcy5udW1lcmljKGBuX2RlX3JlZ2lzdG9zX3ZpYV92ZXJkZV9hdmNgKSwgbmEucm0gPSBUUlVFKSwgLmdyb3VwcyA9ICJkcm9wIikKCmdncGxvdChhdmNfcmVnaWFvX3RlbXBvLCBhZXMoeCA9IE1lc19Bbm8sIHkgPSBUb3RhbF9BVkMsIGNvbG9yID0gYGRpc3RyaXRvX2RhX29jb3JyZW5jaWFgLCBncm91cCA9IGBkaXN0cml0b19kYV9vY29ycmVuY2lhYCkpICsKICBnZW9tX2xpbmUoKSArCiAgbGFicyh0aXRsZSA9ICJFdm9sdcOnw6NvIE1lbnNhbCBkZSBSZWdpc3RvcyBkZSBBVkMgcG9yIERpc3RyaXRvIiwKICAgICAgIHggPSAiTcOqcyIsIHkgPSAiVG90YWwgZGUgQVZDIiwgY29sb3IgPSAiRGlzdHJpdG8iKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKQoKIyMgSXIgYnVzY2FyIG8gbsO6bWVybyBkZSBoYWJpdGFudGVzIHBvciBkaXN0cml0byBlbSBwb3J0dWdhbCBlbSAyMDIyLCAyMDIzIGUgMjAyNCBlIGZhemVyIG3DqWRpYSwgcGFyYSBub3JtYWxpemFyIGUgcG9kZXIgY29tcGFyYXIsIHBvcnF1ZSBvYnZpYW1lbnRlIHF1ZSBubyBwb3J0byBlIGxpc2JvYSBow6EgbWFpb3IgbnVtZXJvIGRlIGF2YyBwb3JxdWUgaMOhIG1haXMgaGFiaXRhbnRlcy4KCiMgVmV0b3IgY29tIGFzIHBvcHVsYcOnw7VlcyBtw6lkaWFzIGVzdGltYWRhcwpwb3B1bGFjYW9fZGlzdHJpdG9zIDwtIGMoCiAgIkxpc2JvYSIgPSAyMzE4OTUyLAogICJQb3J0byIgPSAxODI5NzU4LAogICJTZXTDumJhbCIgPSA4OTM0NjQsCiAgIkJyYWdhIiA9IDg1ODcwOCwKICAiQXZlaXJvIiA9IDcxNzk5OCwKICAiRmFybyIgPSA0NzQ1MDAsCiAgIkxlaXJpYSIgPSA0NzE1NzAsCiAgIlNhbnRhcsOpbSIgPSA0MzY4OTEsCiAgIkNvaW1icmEiID0gNDEzMjI1LAogICJWaXNldSIgPSAzNjQwMjAsCiAgIk1hZGVpcmEiID0gMjU0NjMwLAogICJBw6dvcmVzIiA9IDI0MTQ3MSwKICAiVmlhbmEgZG8gQ2FzdGVsbyIgPSAyMzM2MTAsCiAgIlZpbGEgUmVhbCIgPSAxODUyNjMsCiAgIkNhc3RlbG8gQnJhbmNvIiA9IDE3ODg2MCwKICAiw4l2b3JhIiA9IDE1MzQyNywKICAiQmVqYSIgPSAxNDczNjMsCiAgIkd1YXJkYSIgPSAxNDIxMzEsCiAgIkJyYWdhbsOnYSIgPSAxMjMxMDksCiAgIlBvcnRhbGVncmUiID0gMTA0NTYxCikKCgojIEFkaWNpb25hciBwb3B1bGHDp8OjbyBhbyBEYXRhRnJhbWUKYXZjX3JlZ2lhb190ZW1wbyA8LSBhdmNfcmVnaWFvX3RlbXBvICU+JQogIG11dGF0ZShQb3B1bGFjYW8gPSBwb3B1bGFjYW9fZGlzdHJpdG9zW2BkaXN0cml0b19kYV9vY29ycmVuY2lhYF0sCiAgICAgICAgIFRheGFfQVZDID0gKFRvdGFsX0FWQyAvIFBvcHVsYWNhbykgKiAxMDAwMDApCgojIE3DqWRpYSBkYSB0YXhhIGRlIEFWQyBwb3IgZGlzdHJpdG8KcmFua2luZ19kaXN0cml0b3MgPC0gYXZjX3JlZ2lhb190ZW1wbyAlPiUKICBncm91cF9ieShgZGlzdHJpdG9fZGFfb2NvcnJlbmNpYWApICU+JQogIHN1bW1hcmlzZShNZWRpYV9UYXhhX0FWQyA9IG1lYW4oVGF4YV9BVkMsIG5hLnJtID0gVFJVRSkpICU+JQogIGFycmFuZ2UoZGVzYyhNZWRpYV9UYXhhX0FWQykpCgpwcmludChyYW5raW5nX2Rpc3RyaXRvcykKCmdncGxvdChyYW5raW5nX2Rpc3RyaXRvcywgYWVzKHggPSByZW9yZGVyKGBkaXN0cml0b19kYV9vY29ycmVuY2lhYCwgTWVkaWFfVGF4YV9BVkMpLCB5ID0gTWVkaWFfVGF4YV9BVkMpKSArCiAgZ2VvbV9jb2woZmlsbCA9ICJkYXJrcmVkIikgKwogIGdlb21fdGV4dChhZXMobGFiZWwgPSByb3VuZChNZWRpYV9UYXhhX0FWQywgMSkpLCBoanVzdCA9IC0wLjEsIHNpemUgPSAzKSArCiAgY29vcmRfZmxpcCgpICsKICBsYWJzKHRpdGxlID0gIlN0cm9rZSBSYXRlIGJ5IERpc3RyaWN0IiwKICAgICAgIHggPSAiRGlzdHJpY3QiLCB5ID0gIlJhdGUiKSArCiAgdGhlbWVfbWluaW1hbCgpCgojIFZpc3VhbGl6YXIgYXMgdGF4YXMgZGUgQVZDIGFvIGxvbmdvIGRvIHRlbXBvIHBvciBkaXN0cml0bwpnZ3Bsb3QoYXZjX3JlZ2lhb190ZW1wbywgYWVzKHggPSBNZXNfQW5vLCB5ID0gVGF4YV9BVkMsIGNvbG9yID0gYGRpc3RyaXRvX2RhX29jb3JyZW5jaWFgLCBncm91cCA9IGBkaXN0cml0b19kYV9vY29ycmVuY2lhYCkpICsKICBnZW9tX2xpbmUoKSArCiAgbGFicyh0aXRsZSA9ICJFdm9sdcOnw6NvIE1lbnNhbCBkYSBUYXhhIGRlIEFWQyBwb3IgRGlzdHJpdG8iLAogICAgICAgeCA9ICJNw6pzIiwgeSA9ICJUYXhhIGRlIEFWQyBwb3IgMTAwLjAwMCBoYWJpdGFudGVzIiwgY29sb3IgPSAiRGlzdHJpdG8iKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKQoKI0NvbW8gbsOjbyDDqSBwb3NzaXZlbCBjb21wYXJhciBiZW0gcGVsbyBncsOhZmljbywgdmFtb3MgZmF6ZXIgdGVzdGVzIGVzdGF0aXRpc3RpY29zLiAKCiN2YW1vcyB2ZXIgcHJpbWVpcm8gc2UgbyB0b3RhbF9hdmMgdGVtIGRpc3RyaWJ1acOnw6NvIG5vcm1hbCBlbSB0b2RvcyBvcyBkaXN0cml0b3MKCmdncGxvdChhdmNfcmVnaWFvX3RlbXBvLCBhZXMoeCA9IFRheGFfQVZDKSkgKwogIGdlb21faGlzdG9ncmFtKGJpbnMgPSAxNSwgZmlsbCA9ICJza3libHVlIiwgY29sb3IgPSAiYmxhY2siKSArCiAgZmFjZXRfd3JhcCh+IGBkaXN0cml0b19kYV9vY29ycmVuY2lhYCwgc2NhbGVzID0gImZyZWUiKSArCiAgdGhlbWVfbWluaW1hbCgpCgojIEFwbGljYXIgbyB0ZXN0ZSBzaGFwaXJvIApzaGFwaXJvX3Jlc3VsdHMgPC0gYXZjX3JlZ2lhb190ZW1wbyAlPiUKICBncm91cF9ieShkaXN0cml0b19kYV9vY29ycmVuY2lhKSAlPiUKICBzdW1tYXJpc2UocF92YWx1ZSA9IHNoYXBpcm8udGVzdChUYXhhX0FWQykkcC52YWx1ZSkKCiMgUHJpbnQKcHJpbnQoc2hhcGlyb19yZXN1bHRzKQoKIyBIb21vZ2VuZWlkYWRlIGRhcyB2YXJpw6JuY2lhcyBlbnRyZSBvcyBncnVwb3MKCmxldmVuZV9yZXN1bHQgPC0gbGV2ZW5lVGVzdChUYXhhX0FWQyB+IGRpc3RyaXRvX2RhX29jb3JyZW5jaWEsIGRhdGEgPSBhdmNfcmVnaWFvX3RlbXBvKQoKIyBQcmludGFyIG8gcmVzdWx0YWRvCnByaW50KGxldmVuZV9yZXN1bHQpCgojY29uY2x1c8Ojbzogb3MgZGFkb3Mgc8OjbyBkaXN0cmlidWlkb3Mgbm9ybWFsbWVudGUgZSBhcyB2YXJpw6JuY2lhcyBzw6NvIHNpZ25pZmljYXRpdmFtZW50ZSBkaWZlcmVudGVzLiBMb2dvLCB2YW1vcyBmYXplciBvIHRlc3RlIFdlbGNoIEFOT1ZBIChvbmV3YXkudGVzdCkgcGFyYSBjb21wYXJhciBhcyBtw6lkaWFzIGRhcyB0YXhhcyBkZSBBVkMgcG9yIDEwMC4wMDAgaGFiaXRhbnRlcyBlbnRyZSBkaXN0cml0b3MsIHNlbSBhc3N1bWlyIHZhcmnDom5jaWFzIGlndWFpcy4KCiMgV2VsY2ggQU5PVkEKb25ld2F5LnRlc3QoVGF4YV9BVkMgfiBgZGlzdHJpdG9fZGFfb2NvcnJlbmNpYWAsIGRhdGEgPSBhdmNfcmVnaWFvX3RlbXBvLCB2YXIuZXF1YWwgPSBGQUxTRSkKCiN2YW1vcyB2ZXIgY29tbyBhIHRheGEgbcOpZGlhIGRlIEFWQyBldm9sdWl1IGFvIGxvbmdvIGRvcyBhbm9zIHBvciBkaXN0cml0bwoKYXZjX3JlZ2lhb190ZW1wbyA8LSBhdmNfcmVnaWFvX3RlbXBvICU+JQogIG11dGF0ZShBbm8gPSBzdWJzdHIoTWVzX0FubywgMSwgNCkpICAjIGV4dHJhaSBvcyA0IHByaW1laXJvcyBjYXJhY3RlcmVzIGNvbW8gYW5vCgptZWRpYV9hbnVhbF9kaXN0cml0byA8LSBhdmNfcmVnaWFvX3RlbXBvICU+JQogIGdyb3VwX2J5KEFubywgYGRpc3RyaXRvX2RhX29jb3JyZW5jaWFgKSAlPiUKICBzdW1tYXJpc2UoTWVkaWFfVGF4YV9BVkMgPSBtZWFuKFRheGFfQVZDLCBuYS5ybSA9IFRSVUUpLCAuZ3JvdXBzID0gImRyb3AiKQoKZ2dwbG90KG1lZGlhX2FudWFsX2Rpc3RyaXRvLCBhZXMoeCA9IEFubywgeSA9IE1lZGlhX1RheGFfQVZDLCBjb2xvciA9IGBkaXN0cml0b19kYV9vY29ycmVuY2lhYCwgZ3JvdXAgPSBgZGlzdHJpdG9fZGFfb2NvcnJlbmNpYWApKSArCiAgZ2VvbV9saW5lKHNpemUgPSAxKSArCiAgZ2VvbV9wb2ludChzaXplID0gMS41KSArCiAgbGFicyh0aXRsZSA9ICJFdm9sdcOnw6NvIEFudWFsIGRhIFRheGEgZGUgQVZDIHBvciBEaXN0cml0byIsCiAgICAgICB4ID0gIkFubyIsCiAgICAgICB5ID0gIlRheGEgbcOpZGlhIGRlIEFWQyBwb3IgMTAwLjAwMCBoYWJpdGFudGVzIiwKICAgICAgIGNvbG9yID0gIkRpc3RyaXRvIikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkKCiMgIEhlYXRtYXAgCmdncGxvdChtZWRpYV9hbnVhbF9kaXN0cml0bywgYWVzKHggPSBBbm8sIHkgPSByZW9yZGVyKGBkaXN0cml0b19kYV9vY29ycmVuY2lhYCwgLU1lZGlhX1RheGFfQVZDKSkpICsKICBnZW9tX3RpbGUoYWVzKGZpbGwgPSBNZWRpYV9UYXhhX0FWQyksIGNvbG9yID0gIndoaXRlIikgKwogIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93ID0gIndoaXRlIiwgaGlnaCA9ICJyZWQiKSArCiAgbGFicyh0aXRsZSA9ICJIZWF0IE1hcDogU3Ryb2tlIFJhdGUgYnkgRGlzdHJpY3QgYW5kIFllYXIiLAogICAgICAgeCA9ICJZZWFyIiwKICAgICAgIHkgPSAiRGlzdHJpY3QiLAogICAgICAgZmlsbCA9ICJSYXRlIikgKwogIHRoZW1lX21pbmltYWwoKQoKYGBgCgpgYGB7cn0KCiMjIEEgbWVzbWEgYW7DoWxpc2UgbWFzIHBhcmEgaGlwZXJ0ZW5zb3MgCiMgMS4gRGFkb3MgbWVuc2FpcyBmaWx0cmFkb3MgKDIwMjItMDEgYSAyMDI0LTAyKQpoaXBlcnRlbnNhb190ZW1wbyA8LSBoeXBfZmluYWwgJT4lCiAgbXV0YXRlKE1lc19Bbm8gPSBmb3JtYXQoeW0odGVtcG8pLCAiJVktJW0iKSkgJT4lCiAgZmlsdGVyKE1lc19Bbm8gPj0gIjIwMjItMDEiLCBNZXNfQW5vIDw9ICIyMDI0LTAyIikgJT4lCiAgZ3JvdXBfYnkoTWVzX0FubywgZGlzdHJpdG9zLngpICU+JQogIHN1bW1hcmlzZSgKICAgIFRvdGFsX0hpcGVydGVuc2FvX0NvbnRyb2xhZGEgPSBzdW0oYXMubnVtZXJpYyh0b3RhbCksbmEucm0gPSBUUlVFKSwKICAgIC5ncm91cHMgPSAiZHJvcCIpICU+JQogIG11dGF0ZSggUG9wdWxhY2FvID0gcG9wdWxhY2FvX2Rpc3RyaXRvc1tkaXN0cml0b3MueF0sCiAgICAgICAgICBUYXhhX0hpcGVydGVuc2FvX0NvbnRyb2xhZGEgPSAoVG90YWxfSGlwZXJ0ZW5zYW9fQ29udHJvbGFkYSAvIFBvcHVsYWNhbykgKiAxMDAwMDAKICApJT4lCiAgc3RfZHJvcF9nZW9tZXRyeShoaXBlcnRlbnNhb190ZW1wbyklPiUKICByZW5hbWUoRGlzdHJpdG8gPSBkaXN0cml0b3MueCkKCiMgMi4gVG90YWwgYWN1bXVsYWRvIHBvciBkaXN0cml0bwpoaXBlcnRlbnNhb190b3RhbCA8LSBoaXBlcnRlbnNhb190ZW1wbyAlPiUKICBncm91cF9ieShEaXN0cml0bykgJT4lCiAgc3VtbWFyaXNlKFRvdGFsX0hpcGVydGVuc2FvX0NvbnRyb2xhZGEgPSBzdW0oVG90YWxfSGlwZXJ0ZW5zYW9fQ29udHJvbGFkYSwgbmEucm0gPSBUUlVFKSkgJT4lCiAgYXJyYW5nZShkZXNjKFRvdGFsX0hpcGVydGVuc2FvX0NvbnRyb2xhZGEpKQoKCiMgR3LDoWZpY28gZGUgdG90YWwgYWN1bXVsYWRvCmdncGxvdChoaXBlcnRlbnNhb190b3RhbCwgYWVzKHggPSByZW9yZGVyKERpc3RyaXRvLCAtVG90YWxfSGlwZXJ0ZW5zYW9fQ29udHJvbGFkYSksIHkgPSBUb3RhbF9IaXBlcnRlbnNhb19Db250cm9sYWRhKSkgKwogIGdlb21fY29sKGZpbGwgPSAic3RlZWxibHVlIikgKwogIGdlb21fdGV4dChhZXMobGFiZWwgPSByb3VuZChUb3RhbF9IaXBlcnRlbnNhb19Db250cm9sYWRhKSksIHZqdXN0ID0gLTAuMiwgc2l6ZSA9IDIpICsKICBsYWJzKHRpdGxlID0gIlRvdGFsIFBhdGllbnRzIHdpdGggQ29udHJvbGxlZCBIeXBlcnRlbnNpb24gYnkgRGlzdHJpY3QiLAogICAgICAgeCA9ICJEaXN0cmljdCIsIHkgPSAiUGF0aWVudHMiKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKQoKCiMgRGlzdHJpYnVpw6fDo28gYW8gbG9uZ28gZG8gdGVtcG8gcG9yIGRpc3RyaXRvCgpnZ3Bsb3QoaGlwZXJ0ZW5zYW9fdGVtcG8sIGFlcyh4ID0gTWVzX0FubywgeSA9IFRvdGFsX0hpcGVydGVuc2FvX0NvbnRyb2xhZGEsIGNvbG9yID0gYERpc3RyaXRvYCwgZ3JvdXAgPSBgRGlzdHJpdG9gKSkgKwogIGdlb21fbGluZSgpICsKICBsYWJzKHRpdGxlID0gIkV2b2x1w6fDo28gTWVuc2FsIGRlIFJlZ2lzdG9zIGRlIGhpcGVydGVuc2FvIHBvciBEaXN0cml0byIsCiAgICAgICB4ID0gIk3DqnMiLCB5ID0gIlRvdGFsIGRlIEhpcGVydGVuc8OjbyIsIGNvbG9yID0gIkRpc3RyaXRvIikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkKCgojIDMuIEdyw6FmaWNvIGRlIGV2b2x1w6fDo28gbWVuc2FsIGRhcyB0YXhhcwpnZ3Bsb3QoaGlwZXJ0ZW5zYW9fdGVtcG8sIGFlcyh4ID0gTWVzX0FubywgeSA9IFRheGFfSGlwZXJ0ZW5zYW9fQ29udHJvbGFkYSwgY29sb3IgPSBEaXN0cml0bywgZ3JvdXAgPSBEaXN0cml0bykpICsKICBnZW9tX2xpbmUoKSArCiAgbGFicyh0aXRsZSA9ICJFdm9sdcOnw6NvIG1lbnNhbCBkYSBUYXhhIGRlIEhpcGVydGVuc8OjbyBDb250cm9sYWRhIHBvciBEaXN0cml0byIsCiAgICAgICB4ID0gIk3DqnMiLCB5ID0gIlRheGEgZGUgSGlwZXJ0ZW5zw6NvIHBvciAxMDAuMDAwIGhhYml0YW50ZXMiLCBjb2xvciA9ICJEaXN0cml0byIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMQogICkpCgoKIyA0LiBNw6lkaWEgZGEgdGF4YSBwb3IgZGlzdHJpdG8KcmFua2luZ19kaXN0cml0b3MgPC0gaGlwZXJ0ZW5zYW9fdGVtcG8gJT4lCiAgZ3JvdXBfYnkoRGlzdHJpdG8pICU+JQogIHN1bW1hcmlzZShNZWRpYV9UYXhhX0hpcGVydGVuc2FvX0NvbnRyb2xhZGEgPSBtZWFuKFRheGFfSGlwZXJ0ZW5zYW9fQ29udHJvbGFkYSwgbmEucm0gPSBUUlVFKSkgJT4lCiAgYXJyYW5nZShkZXNjKE1lZGlhX1RheGFfSGlwZXJ0ZW5zYW9fQ29udHJvbGFkYSkpCgojIEdyw6FmaWNvIGRlIHJhbmtpbmcgZGFzIHRheGFzIG3DqWRpYXMKZ2dwbG90KHJhbmtpbmdfZGlzdHJpdG9zLCBhZXMoeCA9IHJlb3JkZXIoRGlzdHJpdG8sIE1lZGlhX1RheGFfSGlwZXJ0ZW5zYW9fQ29udHJvbGFkYSksIHkgPSBNZWRpYV9UYXhhX0hpcGVydGVuc2FvX0NvbnRyb2xhZGEpKSArCiAgZ2VvbV9jb2woZmlsbCA9ICJkYXJrZ3JlZW4iKSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHJvdW5kKE1lZGlhX1RheGFfSGlwZXJ0ZW5zYW9fQ29udHJvbGFkYSwgMSkpLCBoanVzdCA9IC0wLjEsIHNpemUgPSAyKSArCiAgY29vcmRfZmxpcCgpICsKICBsYWJzKHRpdGxlID0gIkNvbnRyb2xsZWQgSHlwZXJ0ZW5zaW9uIFJhdGUgYnkgRGlzdHJpY3QiLAogICAgICAgeCA9ICJEaXN0cmljdCIsIHkgPSAiUmF0ZSIpICsKICB0aGVtZV9taW5pbWFsKCkKCgojIDUuIEhpc3RvZ3JhbWFzIHBvciBkaXN0cml0byAoZGlzdHJpYnVpw6fDo28gZGFzIHRheGFzKQpnZ3Bsb3QoaGlwZXJ0ZW5zYW9fdGVtcG8sIGFlcyh4ID0gVGF4YV9IaXBlcnRlbnNhb19Db250cm9sYWRhKSkgKwogIGdlb21faGlzdG9ncmFtKGJpbnMgPSAxNSwgZmlsbCA9ICJza3libHVlIiwgY29sb3IgPSAiYmxhY2siKSArCiAgZmFjZXRfd3JhcCh+IERpc3RyaXRvLCBzY2FsZXMgPSAiZnJlZSIpICsKICB0aGVtZV9taW5pbWFsKCkKCiMgNi4gVGVzdGUgZGUgbm9ybWFsaWRhZGUgKFNoYXBpcm8tV2lsaykKc2hhcGlyb19yZXN1bHRzIDwtIGhpcGVydGVuc2FvX3RlbXBvICU+JQogIGdyb3VwX2J5KERpc3RyaXRvKSAlPiUKICBzdW1tYXJpc2UocF92YWx1ZSA9IHNoYXBpcm8udGVzdChUYXhhX0hpcGVydGVuc2FvX0NvbnRyb2xhZGEpJHAudmFsdWUpCgpwcmludChzaGFwaXJvX3Jlc3VsdHMpCgojIDcuIFRlc3RlIGRlIGhvbW9nZW5laWRhZGUgZGFzIHZhcmnDom5jaWFzIChMZXZlbmUpCmxldmVuZVRlc3QoVGF4YV9IaXBlcnRlbnNhb19Db250cm9sYWRhIH4gRGlzdHJpdG8sIGRhdGEgPSBoaXBlcnRlbnNhb190ZW1wbykKIAprcnVza2FsLnRlc3QoVGF4YV9IaXBlcnRlbnNhb19Db250cm9sYWRhIH4gRGlzdHJpdG8sIGRhdGEgPSBoaXBlcnRlbnNhb190ZW1wbykKCiMgUGFydGluZG8gZG8gb2JqZXRvIGBoaXBlcnRlbnNhb190ZW1wb2AgasOhIGV4aXN0ZW50ZSBlIGZpbHRyYWRvICgyMDIyLTIwMjQpCgojIDEuIEV4dHJhaXIgbyBhbm8KaGlwZXJ0ZW5zYW9fdGVtcG8gPC0gaGlwZXJ0ZW5zYW9fdGVtcG8gJT4lCiAgbXV0YXRlKEFubyA9IHN1YnN0cihNZXNfQW5vLCAxLCA0KSkKCiMgMi4gQ2FsY3VsYXIgbcOpZGlhIGFudWFsIGRhIHRheGEgcG9yIGRpc3RyaXRvCm1lZGlhX2FudWFsX2Rpc3RyaXRvIDwtIGhpcGVydGVuc2FvX3RlbXBvICU+JQogIGdyb3VwX2J5KEFubywgRGlzdHJpdG8pICU+JQogIHN1bW1hcmlzZShNZWRpYV9UYXhhX0hpcGVydGVuc2FvX0NvbnRyb2xhZGEgPSBtZWFuKFRheGFfSGlwZXJ0ZW5zYW9fQ29udHJvbGFkYSwgbmEucm0gPSBUUlVFKSwgLmdyb3VwcyA9ICJkcm9wIikKCiMgMy4gR3LDoWZpY28gZGUgbGluaGFzOiBFdm9sdcOnw6NvIGFudWFsCmdncGxvdChtZWRpYV9hbnVhbF9kaXN0cml0bywgYWVzKHggPSBBbm8sIHkgPSBNZWRpYV9UYXhhX0hpcGVydGVuc2FvX0NvbnRyb2xhZGEsIGNvbG9yID0gRGlzdHJpdG8sIGdyb3VwID0gRGlzdHJpdG8pKSArCiAgZ2VvbV9saW5lKHNpemUgPSAxKSArCiAgZ2VvbV9wb2ludChzaXplID0gMS41KSArCiAgbGFicyh0aXRsZSA9ICJFdm9sdcOnw6NvIEFudWFsIGRhIFRheGEgZGUgSGlwZXJ0ZW5zw6NvIENvbnRyb2xhZGEgcG9yIERpc3RyaXRvIiwKICAgICAgIHggPSAiQW5vIiwKICAgICAgIHkgPSAiVGF4YSBtw6lkaWEgcG9yIDEwMC4wMDAgaGFiaXRhbnRlcyIsCiAgICAgICBjb2xvciA9ICJEaXN0cml0byIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpCgojIDQuIEhlYXRtYXA6IE1hcGEgZGUgY2Fsb3IgcG9yIGRpc3RyaXRvIGUgYW5vCmdncGxvdChtZWRpYV9hbnVhbF9kaXN0cml0bywgYWVzKHggPSBBbm8sIHkgPSByZW9yZGVyKERpc3RyaXRvLCAtTWVkaWFfVGF4YV9IaXBlcnRlbnNhb19Db250cm9sYWRhKSkpICsKICBnZW9tX3RpbGUoYWVzKGZpbGwgPSBNZWRpYV9UYXhhX0hpcGVydGVuc2FvX0NvbnRyb2xhZGEpLCBjb2xvciA9ICJ3aGl0ZSIpICsKICBzY2FsZV9maWxsX2dyYWRpZW50KGxvdyA9ICJ3aGl0ZSIsIGhpZ2ggPSAiZGFya2dyZWVuIikgKwogIGxhYnModGl0bGUgPSAiSGVhdCBNYXA6IENvbnRyb2xsZWQgSHlwZXJ0ZW5zaW9uIFJhdGUgYnkgRGlzdHJpY3QgYW5kIFllYXIiLAogICAgICAgeCA9ICJZZWFyIiwKICAgICAgIHkgPSAiRGlzdHJpY3QiLAogICAgICAgZmlsbCA9ICJSYXRlIikgKwogIHRoZW1lX21pbmltYWwoKQoKI1ZhbW9zIGFqdXN0YXIgdW1hIHJlZ3Jlc3PDo28gbGluZWFyIGRhIHRheGEgbcOpZGlhIGFudWFsIHZzIGFubyBwYXJhIGNhZGEgZGlzdHJpdG8gZSB2ZXIgbyBjb2VmaWNpZW50ZSBkYSBpbmNsaW5hw6fDo286IAojIENvbnZlcnRlciBvIGFubyBwYXJhIG51bcOpcmljbwptZWRpYV9hbnVhbF9kaXN0cml0byRBbm9fTnVtIDwtIGFzLm51bWVyaWMobWVkaWFfYW51YWxfZGlzdHJpdG8kQW5vKQoKIyBSZWdyZXNzw6NvIGxpbmVhciBwb3IgZGlzdHJpdG8KdGVuZGVuY2lhcyA8LSBtZWRpYV9hbnVhbF9kaXN0cml0byAlPiUKICBncm91cF9ieShEaXN0cml0bykgJT4lCiAgc3VtbWFyaXNlKAogICAgaW5jbGluYWNhbyA9IGNvZWYobG0oTWVkaWFfVGF4YV9IaXBlcnRlbnNhb19Db250cm9sYWRhIH4gQW5vX051bSkpWzJdLAogICAgcF92YWxvciA9IHN1bW1hcnkobG0oTWVkaWFfVGF4YV9IaXBlcnRlbnNhb19Db250cm9sYWRhIH4gQW5vX051bSkpJGNvZWZmaWNpZW50c1syLCA0XQogICkgJT4lCiAgYXJyYW5nZShpbmNsaW5hY2FvKQoKcHJpbnQodGVuZGVuY2lhcykKCiMgQXBsaWNhIG8gdGVzdGUgZGUgTWFubi1LZW5kYWxsIGdsb2JhbG1lbnRlCm1rLnRlc3QobWVkaWFfYW51YWxfZGlzdHJpdG8kTWVkaWFfVGF4YV9IaXBlcnRlbnNhb19Db250cm9sYWRhKQoKbW9kZWxvX2dsb2JhbCA8LSBsbShNZWRpYV9UYXhhX0hpcGVydGVuc2FvX0NvbnRyb2xhZGEgfiBBbm9fTnVtLCBkYXRhID0gbWVkaWFfYW51YWxfZGlzdHJpdG8pCnN1bW1hcnkobW9kZWxvX2dsb2JhbCkKYGBgCgpgYGB7cn0KCiMjIENPTVBBUkHDh8ODTyBDT00gQVMgVEFYQVMgTk9TIEFOT1MgQ09NVU5TCgojIEFWQwphdmNfcmVnaWFvIDwtIGF2YyAlPiUKICBncm91cF9ieShgZGlzdHJpdG9fZGFfb2NvcnJlbmNpYWApICU+JQogIHN1bW1hcmlzZShUb3RhbF9BVkMgPSBzdW0oYXMubnVtZXJpYyhgbl9kZV9yZWdpc3Rvc192aWFfdmVyZGVfYXZjYCksIG5hLnJtID0gVFJVRSkpICU+JQogIHJlbmFtZShEaXN0cml0byA9IGBkaXN0cml0b19kYV9vY29ycmVuY2lhYCkKCiMgSGlwZXJ0ZW5zw6NvCmhpcGVydGVuc2FvX3RvdGFsIDwtIGhpcGVydGVuc2FvX3RlbXBvICU+JQogIGdyb3VwX2J5KERpc3RyaXRvKSAlPiUKICBzdW1tYXJpc2UoVG90YWxfSGlwZXJ0ZW5zYW9fQ29udHJvbGFkYSA9IHN1bShUb3RhbF9IaXBlcnRlbnNhb19Db250cm9sYWRhLCBuYS5ybSA9IFRSVUUpKSAKCiMgSnVudGFyCmRmX3JlbGFjYW8gPC0gZnVsbF9qb2luKGF2Y19yZWdpYW8sIGhpcGVydGVuc2FvX3RvdGFsLCBieSA9ICJEaXN0cml0byIpICU+JQogIG11dGF0ZSgKICAgIFBvcHVsYWNhbyA9IHBvcHVsYWNhb19kaXN0cml0b3NbRGlzdHJpdG9dLAogICAgVGF4YV9BVkMgPSAoVG90YWxfQVZDIC8gUG9wdWxhY2FvKSAqIDEwMDAwMCwKICAgIFRheGFfSGlwZXJ0ZW5zYW9fQ29udHJvbGFkYSA9IChUb3RhbF9IaXBlcnRlbnNhb19Db250cm9sYWRhIC8gUG9wdWxhY2FvKSAqIDEwMDAwMAogICkgJT4lCiAgZHJvcF9uYSgpCmdncGxvdChkZl9yZWxhY2FvLCBhZXMoeCA9IFRheGFfSGlwZXJ0ZW5zYW9fQ29udHJvbGFkYSwgeSA9IFRheGFfQVZDKSkgKwogIGdlb21fcG9pbnQoY29sb3IgPSAiZGFya2JsdWUiLCBzaXplID0gMykgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gVFJVRSwgY29sb3IgPSAicmVkIikgKwogIGdlb21fdGV4dChhZXMobGFiZWwgPSBEaXN0cml0byksIHZqdXN0ID0gLTAuOCwgc2l6ZSA9IDMpICsKICBsYWJzKHRpdGxlID0gIlJlbGF0aW9uc2hpcCBiZXR3ZWVuIENvbnRyb2xsZWQgSHlwZXJ0ZW5zaW9uIFJhdGUgYW5kIFN0cm9rZSBSYXRlIGJ5IERpc3RyaWN0IiwKICAgICAgIHggPSAiQ29udHJvbGxlZCBIeXBlcnRlbnNpb24gUmF0ZSBwZXIgMTAwLDAwMCBpbmhhYml0YW50cyIsCiAgICAgICB5ID0gIlN0cm9rZSBSYXRlIHBlciAxMDAsMDAwIGluaGFiaXRhbnRzIikgKwogIHRoZW1lX21pbmltYWwoKQoKIyB2ZXIgc2UgdGVuaG8gb3V0bGllcnMgCgpib3hwbG90KGRmX3JlbGFjYW8kVGF4YV9IaXBlcnRlbnNhb19Db250cm9sYWRhLAogICAgICAgIG1haW4gPSAiQm94cGxvdCBvZiBDb250cm9sbGVkIEh5cGVydGVuc2lvbiBSYXRlIGJ5IERpc3RyaWN0IiwKICAgICAgICB5bGFiID0gIlJhdGUiKQoKIyBCb3hwbG90IGZvciBTdHJva2UgUmF0ZQpib3hwbG90KGRmX3JlbGFjYW8kVGF4YV9BVkMsCiAgICAgICAgbWFpbiA9ICJCb3hwbG90IG9mIFN0cm9rZSBSYXRlIGJ5IERpc3RyaWN0IiwKICAgICAgICB5bGFiID0gIlJhdGUiKQoKIyBQYXJhIFRheGFfSGlwZXJ0ZW5zYW9fQ29udHJvbGFkYQp4IDwtIGRmX3JlbGFjYW8kVGF4YV9IaXBlcnRlbnNhb19Db250cm9sYWRhClExIDwtIHF1YW50aWxlKHgsIDAuMjUsIG5hLnJtID0gVFJVRSkKUTMgPC0gcXVhbnRpbGUoeCwgMC43NSwgbmEucm0gPSBUUlVFKQpJUVIgPC0gUTMgLSBRMQoKIyBMaW1pdGVzIGluZmVyaW9yIGUgc3VwZXJpb3IKbGltX2luZiA8LSBRMSAtIDEuNSAqIElRUgpsaW1fc3VwIDwtIFEzICsgMS41ICogSVFSCgojIFZlciBxdWFpcyBzw6NvIG9zIG91dGxpZXJzCm91dGxpZXJzIDwtIHhbeCA8IGxpbV9pbmYgfCB4ID4gbGltX3N1cF0KcHJpbnQob3V0bGllcnMpCgojTsOjbyB0ZW0gb3V0bGllcnMKIwojIENvcnJlbGHDp8Ojbwpjb3IudGVzdChkZl9yZWxhY2FvJFRheGFfSGlwZXJ0ZW5zYW9fQ29udHJvbGFkYSwgZGZfcmVsYWNhbyRUYXhhX0FWQywgbWV0aG9kID0gInBlYXJzb24iKQoKCiMgUmVncmVzc8OjbwpzdW1tYXJ5KGxtKFRheGFfQVZDIH4gVGF4YV9IaXBlcnRlbnNhb19Db250cm9sYWRhLCBkYXRhID0gZGZfcmVsYWNhbykpCmBgYAoKYGBge3J9CgojIEp1bnRhciBwb3IgRGlzdHJpdG8gZSBNw6pzCgoKYXZjX3JlZ2lhb190ZW1wbyA8LSBhdmNfcmVnaWFvX3RlbXBvICU+JQogIHJlbmFtZShEaXN0cml0byA9IGRpc3RyaXRvX2RhX29jb3JyZW5jaWEpCgoKZGFkb3NfbWVuc2Fpc19jb21iaW5hZG9zIDwtIGlubmVyX2pvaW4oYXZjX3JlZ2lhb190ZW1wbywgaGlwZXJ0ZW5zYW9fdGVtcG8sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJ5ID0gYygiTWVzX0FubyIsICJEaXN0cml0byIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdWZmaXggPSBjKCJfQVZDIiwgIl9IaXBlcnRlbnNhbyIpKSAlPiUKICBzZWxlY3QoTWVzX0FubywgRGlzdHJpdG8sIFRheGFfQVZDLCBUYXhhX0hpcGVydGVuc2FvX0NvbnRyb2xhZGEpCgojIENvcnJlbGFjzKdhzINvIGRlIFBlYXJzb24gcG9yIGRpc3RyaXRvCmNvcnJlbGFjb2VzX2Rpc3RyaXRvIDwtIGRhZG9zX21lbnNhaXNfY29tYmluYWRvcyAlPiUKICBncm91cF9ieShEaXN0cml0bykgJT4lCiAgc3VtbWFyaXNlKAogICAgY29ycmVsYWNhbyA9IGNvcihUYXhhX0FWQywgVGF4YV9IaXBlcnRlbnNhb19Db250cm9sYWRhLCB1c2UgPSAiY29tcGxldGUub2JzIiwgbWV0aG9kID0gInBlYXJzb24iKSwKICAgIC5ncm91cHMgPSAiZHJvcCIKICApICU+JQogIGFycmFuZ2UoY29ycmVsYWNhbykKCnByaW50KGNvcnJlbGFjb2VzX2Rpc3RyaXRvKQoKZ2dwbG90KGNvcnJlbGFjb2VzX2Rpc3RyaXRvLCBhZXMoeCA9IHJlb3JkZXIoRGlzdHJpdG8sIGNvcnJlbGFjYW8pLCB5ID0gY29ycmVsYWNhbykpICsKICBnZW9tX2NvbChmaWxsID0gInB1cnBsZSIpICsKICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcm91bmQoY29ycmVsYWNhbywgMikpLCBoanVzdCA9IC0wLjIsIHNpemUgPSAzKSArCiAgY29vcmRfZmxpcCgpICsKICBsYWJzKHRpdGxlID0gIkNvcnJlbGHDp8OjbyBlbnRyZSBUYXhhIGRlIEFWQyBlIEhpcGVydGVuc8OjbyBDb250cm9sYWRhIHBvciBEaXN0cml0byIsCiAgICAgICB4ID0gIkRpc3RyaXRvIiwgeSA9ICJDb3JyZWxhw6fDo28gKHIpIikgKwogIHRoZW1lX21pbmltYWwoKQoKIyBKdW50YXIgb3MgZGFkb3MgbWVuc2FpcwpkYWRvc19tZW5zYWlzX2NvbWJpbmFkb3MgPC0gaW5uZXJfam9pbihhdmNfcmVnaWFvX3RlbXBvLCBoaXBlcnRlbnNhb190ZW1wbywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnkgPSBjKCJNZXNfQW5vIiwgIkRpc3RyaXRvIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1ZmZpeCA9IGMoIl9BVkMiLCAiX0hpcGVydGVuc2FvIikpICU+JQogIHNlbGVjdChNZXNfQW5vLCBEaXN0cml0bywgVGF4YV9BVkMsIFRheGFfSGlwZXJ0ZW5zYW9fQ29udHJvbGFkYSkKCiMgQ2FsY3VsYXIgY29ycmVsYcOnw6NvIGUgcC12YWxvciBwb3IgZGlzdHJpdG8KY29ycmVsYWNvZXNfZGlzdHJpdG8gPC0gZGFkb3NfbWVuc2Fpc19jb21iaW5hZG9zICU+JQogIGdyb3VwX2J5KERpc3RyaXRvKSAlPiUKICBzdW1tYXJpc2UoCiAgICByID0gY29yKFRheGFfQVZDLCBUYXhhX0hpcGVydGVuc2FvX0NvbnRyb2xhZGEsIHVzZSA9ICJjb21wbGV0ZS5vYnMiLCBtZXRob2QgPSAicGVhcnNvbiIpLAogICAgcF92YWx1ZSA9IGNvci50ZXN0KFRheGFfQVZDLCBUYXhhX0hpcGVydGVuc2FvX0NvbnRyb2xhZGEpJHAudmFsdWUsCiAgICAuZ3JvdXBzID0gImRyb3AiCiAgKSAlPiUKICBhcnJhbmdlKHIpCgojIFZlciBkaXN0cml0b3MgY29tIGNvcnJlbGHDp8OjbyBuZWdhdGl2YSBzaWduaWZpY2F0aXZhCmNvcnJlbGFjb2VzX3NpZ25pZmljYXRpdmFzIDwtIGNvcnJlbGFjb2VzX2Rpc3RyaXRvICU+JQogIGZpbHRlcihyIDwgLTAuMywgcF92YWx1ZSA8IDAuMDUpCgpwcmludChjb3JyZWxhY29lc19zaWduaWZpY2F0aXZhcykKCmdncGxvdChjb3JyZWxhY29lc19kaXN0cml0bywgYWVzKHggPSByZW9yZGVyKERpc3RyaXRvLCByKSwgeSA9IHIsIGZpbGwgPSBwX3ZhbHVlIDwgMC4wNSAmIHIgPCAtMC4zKSkgKwogIGdlb21fY29sKCkgKwogIGdlb21fdGV4dChhZXMobGFiZWwgPSByb3VuZChyLCAyKSksIGhqdXN0ID0gLTAuMiwgc2l6ZSA9IDMpICsKICBjb29yZF9mbGlwKCkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoImdyZXk3MCIsICJkYXJrcmVkIiksIGxhYmVscyA9IGMoIk7Do28gc2lnbmlmaWNhdGl2YSIsICJTaWduaWZpY2F0aXZhIiksIG5hbWUgPSAiQ29ycmVsYcOnw6NvIG5lZ2F0aXZhIHNpZ25pZmljYXRpdmEiKSArCiAgbGFicyh0aXRsZSA9ICJDb3JyZWxhw6fDo28gZW50cmUgSGlwZXJ0ZW5zw6NvIENvbnRyb2xhZGEgZSBBVkMgcG9yIERpc3RyaXRvIiwKICAgICAgIHggPSAiRGlzdHJpdG8iLCB5ID0gIkNvZWZpY2llbnRlIGRlIENvcnJlbGHDp8OjbyAocikiKSArCiAgdGhlbWVfbWluaW1hbCgpCgoKYGBgCgoKYGBge3J9CiMgQ29ycmVsYcOnw6NvIGVudHJlIGhpcGVydGVuw6fDo28gZSBhdmMgY29tIGFzIHRheGFzCiMgQ29uc2lkZXJhbmRvIG8gbWFpb3IgcGVyw61vZG8gZGUgdGVtcG8gZGFkbyBwZWxhIGRhdGEKCiNwb3B1bGHDp8OjbyBtw6lkaWEgcHIgZGlzdHJpdG9zIGVudHJlIDIwMTUgZSAyMDIzCnBvcHVsYWNhb19tZWRpYSA8LSBjKAogIExpc2JvYSA9IDIyNzYyOTMsCiAgUG9ydG8gPSAxNzk1NTQ5LAogIFNldHViYWwgPSA4Njk3NzAsCiAgQnJhZ2EgPSA4NDM2OTcsCiAgQXZlaXJvID0gNzAzMDIyLAogIEZhcm8gPSA0NjI1MjIsCiAgTGVpcmlhID0gNDU3MjQyLAogIFNhbnRhcmVtID0gNDM3NTIwLAogIENvaW1icmEgPSA0MTE5MzUsCiAgVmlzZXUgPSAzNjIyNzUsCiAgTWFkZWlyYSA9IDI1MTAyNSwKICBBY29yZXMgPSAyMzgxMjcsCiAgVmlhbmFfZG9fQ2FzdGVsbyA9IDIzNDY3MiwKICBWaWxhX1JlYWwgPSAxOTU0MjIsCiAgQ2FzdGVsb19CcmFuY28gPSAxODM5OTYsCiAgRXZvcmEgPSAxNTU0NDEsCiAgQmVqYSA9IDE0NDc3MiwKICBHdWFyZGEgPSAxNDg5MzIsCiAgQnJhZ2FuY2EgPSAxMjczNTYsCiAgUG9ydGFsZWdyZSA9IDEwOTk3NQopCgpoaXBlcnRlbnNhb190ZW1wb19hbGwgPC0gaHlwX2ZpbmFsICU+JQogIG11dGF0ZShNZXNfQW5vID0gZm9ybWF0KHltKHRlbXBvKSwgIiVZLSVtIikpICU+JQogIGdyb3VwX2J5KE1lc19Bbm8sIGRpc3RyaXRvcy54KSAlPiUKICBzdW1tYXJpc2UoCiAgICBUb3RhbF9IaXBlcnRlbnNhb19Db250cm9sYWRhID0gc3VtKGFzLm51bWVyaWModG90YWwpLCBuYS5ybSA9IFRSVUUpLAogICAgLmdyb3VwcyA9ICJkcm9wIgogICkgJT4lCiAgbXV0YXRlKAogICAgUG9wdWxhY2FvID0gcG9wdWxhY2FvX21lZGlhW2Rpc3RyaXRvcy54XSwKICAgIFRheGFfSGlwZXJ0ZW5zYW9fQ29udHJvbGFkYSA9IChUb3RhbF9IaXBlcnRlbnNhb19Db250cm9sYWRhIC8gcG9wdWxhY2FvX21lZGlhKSAqIDEwMDAwMAogICkKCgoKaGlwZXJ0ZW5zYW9fdG90YWxfMjAxNSA8LSBoaXBlcnRlbnNhb190ZW1wb19hbGwgJT4lCiAgZ3JvdXBfYnkoZGlzdHJpdG9zLngpICU+JQogIHN1bW1hcmlzZShUYXhhX0hpcGVydGVuc2FvX0NvbnRyb2xhZGEgPSBzdW0oVGF4YV9IaXBlcnRlbnNhb19Db250cm9sYWRhLCBuYS5ybSA9IFRSVUUpKSAlPiUKICBhcnJhbmdlKGRlc2MoVGF4YV9IaXBlcnRlbnNhb19Db250cm9sYWRhKSklPiUKICByZW5hbWUoRGlzdHJpdG8gPSBkaXN0cml0b3MueCkKCgphdmNfaGlwZXJ0ZW5zYW9fYWxsIDwtIGF2Y19yZWdpYW9fdGVtcG8gJT4lCiAgaW5uZXJfam9pbihoaXBlcnRlbnNhb190b3RhbF8yMDE1LCBieSA9ICJEaXN0cml0byIpCgpnZ3Bsb3QoYXZjX2hpcGVydGVuc2FvX2FsbCwgYWVzKHggPSBUYXhhX0hpcGVydGVuc2FvX0NvbnRyb2xhZGEsIHkgPSBUYXhhX0FWQykpICsKICBnZW9tX3BvaW50KGNvbG9yID0gInN0ZWVsYmx1ZSIsIHNpemUgPSAzKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSwgY29sb3IgPSAicmVkIikgKwogIGxhYnModGl0bGUgPSAiQ29ycmVsYXRpb24gYmV0d2VlbiBDb250cm9sbGVkIEh5cGVydGVuc2lvbiBSYXRlIGFuZCBTdHJva2UgUmF0ZSBieSBEaXN0cmljdCIsCiAgICAgICB4ID0gIkNvbnRyb2xsZWQgSHlwZXJ0ZW5zaW9uIFJhdGUgZnJvbSAyMDE1IHRvIDIwMjQiLAogICAgICAgeSA9ICJTdHJva2UgUmF0ZSBmcm9tIDIwMjIgdG8gMjAyNCIpICsKICB0aGVtZV9taW5pbWFsKCkKCmNvcnJlbGFjYW8gPC0gY29yKGF2Y19oaXBlcnRlbnNhb19hbGwkVGF4YV9IaXBlcnRlbnNhb19Db250cm9sYWRhLCBhdmNfaGlwZXJ0ZW5zYW9fYWxsJFRheGFfQVZDKQpwcmludChjb3JyZWxhY2FvKQoKCiNUZXN0ZXMgbsOjbyBwYXJhbcOpdHJpY29zCiNjb3JyZWxhw6fDo28gZGUgc3BlYXJtYW4gLSBtb27Ds3RvbmEgbsOjbyBsaW5lYXIKYyA8LSBjb3IoYXZjX2hpcGVydGVuc2FvX2FsbCRUYXhhX0hpcGVydGVuc2FvX0NvbnRyb2xhZGEsIGF2Y19oaXBlcnRlbnNhb19hbGwkVGF4YV9BVkMsIG1ldGhvZCA9ICJzcGVhcm1hbiIpCnByaW50KGMpCgojIG1lZGlkYSBuw6NvIHBhcmFtw6l0cmljYSBxdWUgYXZhbGlhIGEgYXNzb2NpYcOnw6NvIG1vbm90w7RuaWNhIGVudHJlIGR1YXMgdmFyacOhdmVpcy4gT3Ugc2VqYSwgdmVyaWZpY2Egc2UsIMOgIG1lZGlkYSBxdWUgdW1hIHZhcmnDoXZlbCBhdW1lbnRhLCBhIG91dHJhIHRlbmRlIGEgYXVtZW50YXIgKG91IGRpbWludWlyKSwgc2VtIGV4aWdpciB1bWEgcmVsYcOnw6NvIGxpbmVhci4KI2V4aXN0ZSB1bWEgY29ycmVsYcOnw6NvIG5lYWd0aXZhIGZyYWNhICgtMC4yMTI1NzA0KSBlbnRyZSBhcyBkdWFzIHZhcmnDoXZlaXMKCgojY29yZWVsYcOnw6NvIGRlIGtlbmRhbGwgLSBtZWRlIGEgZm9yw6dhIGUgYSBkaXJlw6fDo28gZGEgcmVsYcOnw6NvIG1vbm90w7RuaWNhCmsgPC0gY29yKGF2Y19oaXBlcnRlbnNhb19hbGwkVGF4YV9IaXBlcnRlbnNhb19Db250cm9sYWRhLCBhdmNfaGlwZXJ0ZW5zYW9fYWxsJFRheGFfQVZDLCBtZXRob2QgPSAia2VuZGFsbCIpCnByaW50KGspCgpyZXN1bHRhZG8gPC0gY29yLnRlc3QoYXZjX2hpcGVydGVuc2FvX2FsbCRUYXhhX0hpcGVydGVuc2FvX0NvbnRyb2xhZGEsIGF2Y19oaXBlcnRlbnNhb19hbGwkVGF4YV9BVkMsCiAgICAgICAgICAgICAgICAgICAgICBtZXRob2QgPSAia2VuZGFsbCIpCnByaW50KHJlc3VsdGFkbykKCiNleGlzdGUgdW1hIGNvcnJlbGHDp8OjbyBuZWdhdGl2YSBmcmFjYSAoLTAuMTU4OTI5OCkgZW50cmUgYXMgZHVhcyB2YXJpw6F2ZWlzCiMgMS43MmUtMDYgPCAwLDA1OiBBIGNvcnJlbGHDp8OjbyDDqSBlc3RhdGlzdGljYW1lbnRlIHNpZ25pZmljYXRpdmEsIGVtYm9yYSBmcmFjYS4KYGBgCgoKYGBge3J9CiNjb3JyZWxhw6fDo28gQVZDIGUgaGlwZXJ0ZW5zw6NvIFPDkyBub3MgYW5vcyBlbSBjb211bQoKCmF2Y19oaXBlcnRlbnNhbyA8LSBhdmNfcmVnaWFvICAlPiUKICBpbm5lcl9qb2luKGhpcGVydGVuc2FvX3RvdGFsLCBieSA9ICJEaXN0cml0byIpCgpnZ3Bsb3QoYXZjX2hpcGVydGVuc2FvLCBhZXMoeCA9IFRvdGFsX0hpcGVydGVuc2FvX0NvbnRyb2xhZGEsIHkgPSBUb3RhbF9BVkMpKSArCiAgZ2VvbV9wb2ludChjb2xvciA9ICJzdGVlbGJsdWUiLCBzaXplID0gMykgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gRkFMU0UsIGNvbG9yID0gInJlZCIpICsKICBsYWJzKHRpdGxlID0gIkNvcnJlbGHDp8OjbyBlbnRyZSBIaXBlcnRlbnPDo28gQ29udHJvbGFkYSBlIFJlZ2lzdG9zIGRlIEFWQyBwb3IgRGlzdHJpdG8iLAogICAgICAgeCA9ICJUb3RhbCBkZSBIaXBlcnRlbnNvcyBDb250cm9sYWRvcyIsCiAgICAgICB5ID0gIlRvdGFsIGRlIFJlZ2lzdG9zIGRlIEFWQyIpICsKICB0aGVtZV9taW5pbWFsKCkKCmNvcnJlbGFjYW8gPC0gY29yKGF2Y19oaXBlcnRlbnNhbyRUb3RhbF9IaXBlcnRlbnNhb19Db250cm9sYWRhLCBhdmNfaGlwZXJ0ZW5zYW8kVG90YWxfQVZDKQpwcmludChjb3JyZWxhY2FvKQpgYGAKYGBgCg==